使用 API Gateway Lambda 授权方 - Amazon API Gateway

使用 API Gateway Lambda 授权方

Lambda 授权方(以前称为自定义授权方)是一种 API Gateway 功能,该功能使用 Lambda 函数来控制对 API 的访问。

如果您要实施使用持有者令牌身份验证策略(如 OAuth 或 SAML)或使用请求参数来确定调用方的身份的自定义授权架构,Lambda 授权方将很有用。

当客户端向您的 API 的方法之一发出请求时,API Gateway 将调用您的 Lambda 授权方,从而采用调用方的身份作为输入并返回 IAM 策略作为输出。

Lambda 授权方有两种类型:

  • 基于令牌的 Lambda 授权方(又称为 TOKEN 授权方)接收持有者令牌中的调用方身份,如 JSON Web 令牌 (JWT) 或 OAuth 令牌。有关示例应用程序,请参阅 GitHub 中的 Open Banking Brazil - Authorization Samples(巴西开放银行-授权示例)。

  • 基于请求参数 的 Lambda 授权方(又称为 REQUEST 授权方)接收标头、查询字符串参数、stageVariables$context 变量的组合中的调用方身份。

    对于 WebSocket API,仅支持基于请求参数的授权方。

您可以通过另一个AWS账户(与您在其中创建 API 的账户不同)来使用 AWS Lambda 函数。有关更多信息,请参阅配置跨账户 Lambda 授权方

例如 Lambda 函数,请参阅 GitHub 上的 aws-apigateway-lambda-authorizer-blueprints

Lambda 授权方身份验证工作流程

下图说明了 Lambda 授权方的授权工作流程。


        API Gateway Lambda 授权工作流程
API Gateway Lambda 授权工作流程
  1. 客户端对 API Gateway API 方法调用方法,同时传递持有者令牌或请求参数。

  2. API Gateway 检查是否为该方法配置了 Lambda 授权方。如果是,API Gateway 调用 Lambda 函数。

  3. Lambda 函数通过以下方式对调用方进行身份验证:

    • 调用 OAuth 提供商以获取 OAuth 访问令牌。

    • 调用 SAML 提供商以获取 SAML 断言。

    • 基于请求参数值生成 IAM 策略。

    • 从数据库中检索凭证。

  4. 如果调用成功,Lambda 函数将通过返回一个包含至少一个 IAM 策略和一个委托人标识符的输出对象来授予访问权限。

  5. API Gateway 对策略进行评估。

    • 如果拒绝访问,API Gateway 将返回一个合适的 HTTP 状态代码,如 403 ACCESS_DENIED

    • 如果允许访问,API Gateway 将执行该方法。如果在授权方设备中启用了缓存,API Gateway 还将缓存策略,以便 Lambda 授权方函数无需再次进行调用。

创建 API Gateway Lambda 授权方的步骤

要创建 Lambda 授权方,您需要执行以下任务:

  1. 在 Lambda 控制台中创建 Lambda 授权方函数,如 在 Lambda 控制台中创建 API Gateway Lambda 授权方函数中所述。您可以使用其中一个蓝图示例作为起点并根据需要自定义输入输出

  2. 将 Lambda 函数作为 API Gateway Authorizer 并将 API 方法配置为需要它,如使用 API Gateway 控制台配置 Lambda 授权方中所述。或者,如果您需要跨账户 Lambda 授权方,请参阅配置跨账户 Lambda 授权方

    注意

    您也可以通过使用 AWS CLI 或 AWS 开发工具包来配置授权方。

  3. 通过使用 Postman 测试您的授权方,如使用 API Gateway Lambda 授权方调用 API中所述。

在 Lambda 控制台中创建 API Gateway Lambda 授权方函数

在配置 Lambda 授权方之前,您必须先创建用于实施逻辑以对调用方进行授权和(如有必要)身份验证的 Lambda 函数。Lambda 控制台提供一个 Python 蓝图,您可以通过选择使用蓝图并选择 api-gateway-authorizer-python 蓝图来使用该蓝图。否则,您将要使用 awslabs GitHub 存储库中的其中一个蓝图作为起点。

对于此部分中的示例 Lambda 授权方函数(未调用其他服务),您可以使用内置的 AWSLambdaBasicExecutionRole。在为您自己的 API Gateway Lambda 授权方创建 Lambda 函数时,如果授权方调用其他 AWS 服务,则需要为 Lambda 函数分配 IAM 执行角色。要创建该角色,请按照 AWS Lambda 执行角色中的说明操作。

有关更多示例 Lambda 函数,请参阅 GitHub 上的 aws-apigateway-lambda-authorizer-blueprints。有关示例应用程序,请参阅 GitHub 中的 Open Banking Brazil - Authorization Samples(巴西开放银行-授权示例)。

示例:创建基于令牌的 Lambda 授权方函数

要创建基于令牌的 Lambda 授权方函数,请在 API Gateway 控制台中输入以下 Node.js 代码,并在 Lambda 控制台中测试它,如下所示。

  1. 在 Lambda 控制台中,选择创建函数

  2. 选择 Author from scratch (从头开始创作)

  3. 输入函数的名称。

  4. 选择创建函数

  5. 在编码编辑器中复制/粘贴以下代码。

    // A simple token-based authorizer example to demonstrate how to use an authorization token // to allow or deny a request. In this example, the caller named 'user' is allowed to invoke // a request if the client-supplied token value is 'allow'. The caller is not allowed to invoke // the request if the token value is 'deny'. If the token value is 'unauthorized' or an empty // string, the authorizer function returns an HTTP 401 status code. For any other token value, // the authorizer returns an HTTP 500 status code. // Note that token values are case-sensitive. export const handler = function(event, context, callback) { var token = event.authorizationToken; switch (token) { case 'allow': callback(null, generatePolicy('user', 'Allow', event.methodArn)); break; case 'deny': callback(null, generatePolicy('user', 'Deny', event.methodArn)); break; case 'unauthorized': callback("Unauthorized"); // Return a 401 Unauthorized response break; default: callback("Error: Invalid token"); // Return a 500 Invalid token response } }; // Help function to generate an IAM policy var generatePolicy = function(principalId, effect, resource) { var authResponse = {}; authResponse.principalId = principalId; if (effect && resource) { var policyDocument = {}; policyDocument.Version = '2012-10-17'; policyDocument.Statement = []; var statementOne = {}; statementOne.Action = 'execute-api:Invoke'; statementOne.Effect = effect; statementOne.Resource = resource; policyDocument.Statement[0] = statementOne; authResponse.policyDocument = policyDocument; } // Optional output with custom properties of the String, Number or Boolean type. authResponse.context = { "stringKey": "stringval", "numberKey": 123, "booleanKey": true }; return authResponse; }
  6. 选择 Deploy (部署)

  7. 在 API Gateway 控制台中,创建一个简单的 API(如果您还没有这样做)。

  8. 从 API 列表中选择您的 API。

  9. 选择 Authorizers (授权方)

  10. 选择 Create New Authorizer (创建新授权方)

  11. 输入授权方的名称。

  12. 对于类型,请选择 Lambda。

  13. 对于 Lambda 函数,选择您在其中创建 Lambda 授权方函数的区域并从下拉列表中选择函数名称。

  14. Lambda 调用角色留空。

  15. 对于 Lambda 事件负载,选择令牌

  16. 对于 Token Source (令牌来源),输入 authorizationToken

  17. 选择 Create (创建),然后选择 Grant & Create (授权与创建)

  18. 选择 Test (测试)

  19. 对于 authorizationToken 值,输入 allow

  20. 选择 Test (测试)

在此示例中,当 API 接收方法请求时,API Gateway 将源令牌传递到 event.authorizationToken 属性中的此 Lambda 授权方函数。Lambda 授权方函数将读取令牌并按下所示做出行为:

  • 如果令牌值为 'allow',授权方函数的测试将返回 200 OK HTTP 响应和 IAM policy(类似于以下内容)并且方法请求成功:

    { "Version": "2012-10-17", "Statement": [ { "Action": "execute-api:Invoke", "Effect": "Allow", "Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/" } ] }
  • 如果令牌值为 'deny',授权方函数的测试将返回 200 OK HTTP 响应和 Deny IAM policy(类似于以下内容)并且方法请求失败:

    { "Version": "2012-10-17", "Statement": [ { "Action": "execute-api:Invoke", "Effect": "Deny", "Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/" } ] }
    注意

    在测试环境之外,授权方函数将返回 403 Forbidden HTTP 响应并且方法请求失败。

  • 如果令牌值为 'unauthorized' 或空字符串,授权方函数的测试将返回 401 Unauthorized HTTP 响应并且方法调用失败。

  • 如果令牌为任何其他内容,客户端将收到 500 Invalid token 响应并且方法调用失败。

注意

在生产代码中,您可能需要先对用户进行身份验证,然后才能授予授权。如果这样,您也可以通过调用身份验证提供商(如该提供商的文档中的指示)在 Lambda 函数中添加身份验证逻辑。

除了返回 IAM 策略之外,Lambda 授权方函数还必须返回调用方的委托人标识符。它还可以选择返回一个 context 对象(包含可传入集成后端的其他信息)。有关更多信息,请参阅来自 Amazon API Gateway Lambda 授权方的输出

示例:创建基于请求的 Lambda 授权方函数

要创建基于请求的 Lambda 授权方函数,请在 API Gateway 控制台中输入以下 Node.js 代码,并在 Lambda 控制台中测试它,如下所示。

  1. 在 Lambda 控制台中,选择创建函数

  2. 选择 Author from scratch (从头开始创作)

  3. 输入函数的名称。

  4. 选择创建函数

  5. 在编码编辑器中复制/粘贴以下代码。

    export const handler = function(event, context, callback) { console.log('Received event:', JSON.stringify(event, null, 2)); // A simple request-based authorizer example to demonstrate how to use request // parameters to allow or deny a request. In this example, a request is // authorized if the client-supplied headerauth1 header, QueryString1 // query parameter, and stage variable of StageVar1 all match // specified values of 'headerValue1', 'queryValue1', and 'stageValue1', // respectively. // Retrieve request parameters from the Lambda function input: var headers = event.headers; var queryStringParameters = event.queryStringParameters; var pathParameters = event.pathParameters; var stageVariables = event.stageVariables; // Parse the input for the parameter values var tmp = event.methodArn.split(':'); var apiGatewayArnTmp = tmp[5].split('/'); var awsAccountId = tmp[4]; var region = tmp[3]; var restApiId = apiGatewayArnTmp[0]; var stage = apiGatewayArnTmp[1]; var method = apiGatewayArnTmp[2]; var resource = '/'; // root resource if (apiGatewayArnTmp[3]) { resource += apiGatewayArnTmp[3]; } // Perform authorization to return the Allow policy for correct parameters and // the 'Unauthorized' error, otherwise. var authResponse = {}; var condition = {}; condition.IpAddress = {}; if (headers.headerauth1 === "headerValue1" && queryStringParameters.QueryString1 === "queryValue1" && stageVariables.StageVar1 === "stageValue1") { callback(null, generateAllow('me', event.methodArn)); } else { callback("Unauthorized"); } } // Help function to generate an IAM policy var generatePolicy = function(principalId, effect, resource) { // Required output: var authResponse = {}; authResponse.principalId = principalId; if (effect && resource) { var policyDocument = {}; policyDocument.Version = '2012-10-17'; // default version policyDocument.Statement = []; var statementOne = {}; statementOne.Action = 'execute-api:Invoke'; // default action statementOne.Effect = effect; statementOne.Resource = resource; policyDocument.Statement[0] = statementOne; authResponse.policyDocument = policyDocument; } // Optional output with custom properties of the String, Number or Boolean type. authResponse.context = { "stringKey": "stringval", "numberKey": 123, "booleanKey": true }; return authResponse; } var generateAllow = function(principalId, resource) { return generatePolicy(principalId, 'Allow', resource); } var generateDeny = function(principalId, resource) { return generatePolicy(principalId, 'Deny', resource); }
  6. 选择 Deploy (部署)

  7. 在 API Gateway 控制台中,创建一个简单的 API(如果您还没有这样做)。

  8. 从 API 列表中选择您的 API。

  9. 选择 Authorizers (授权方)

  10. 选择 Create New Authorizer (创建新授权方)

  11. 输入授权方的名称。

  12. 对于类型,请选择 Lambda。

  13. 对于 Lambda 函数,选择您在其中创建 Lambda 授权方函数的区域并从下拉列表中选择函数名称。

  14. Lambda 调用角色留空。

  15. 对于 Lambda 事件负载,选择请求

  16. 身份源下,添加名为 headerauth1标头、名为 QueryString1查询字符串和名为 StageVar1阶段变量

  17. 选择 Create (创建),然后选择 Grant & Create (授权与创建)

  18. 选择 Test (测试)

  19. 对于 headerauth1,输入 headerValue1。对于 QueryString1,输入 queryValue1。对于 StageVar1,输入 stageValue1

  20. 选择 Test (测试)

在此示例中,Lambda 授权方函数将检查输入参数并按如下所示操作:

  • 如果所有必需的参数值匹配预期值,该授权方函数将返回 200 OK HTTP 响应和 IAM 策略(类似于以下内容)并且方法请求成功:

    { "Version": "2012-10-17", "Statement": [ { "Action": "execute-api:Invoke", "Effect": "Allow", "Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/" } ] }
  • 否则,授权方函数将返回 401 Unauthorized HTTP 响应并且方法调用失败。

注意

在生产代码中,您可能需要先对用户进行身份验证,然后才能授予授权。如果这样,您也可以通过调用身份验证提供商(如该提供商的文档中的指示)在 Lambda 函数中添加身份验证逻辑。

除了返回 IAM 策略之外,Lambda 授权方函数还必须返回调用方的委托人标识符。它还可以选择返回一个 context 对象(包含可传入集成后端的其他信息)。有关更多信息,请参阅来自 Amazon API Gateway Lambda 授权方的输出