Amazon API Gateway
开发人员指南
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

使用 API Gateway Lambda 授权方

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

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

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

有两种类型的 Lambda 授权方:

  • 基于令牌的 Lambda 授权方(又称为 TOKEN 授权方)接收持有者令牌中的调用方身份,如 JSON Web 令牌 (JWT) 或 OAuth 令牌。

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

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

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

如果您已使用 Amazon Cognito 用户池 来管理您的用户账户,或您正在考虑这样做,则您可能要考虑使用 Amazon Cognito 用户池作为 API 的授权方,而不是 Lambda 授权方。

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

要查看 .NET Lambda 授权方的示例,请观看在 .NET Core 2.0 中创建 API Gateway 自定义授权方视频。

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 授权方并将 API 方法配置为需要它,如使用 API Gateway 控制台配置 Lambda 授权方中所述。或者,如果您需要跨账户 Lambda 授权方,请参阅配置跨账户 Lambda 授权方

    注意

    也可以使用 AWS CLI 或 AWS 开发工具包来配置授权方。请参阅使用 AWS CLI 或 AWS 开发工具包配置 Lambda 授权方

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

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

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

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

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

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

  1. 在 Lambda 控制台,选择 Create function (创建函数)

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

  3. 输入函数的名称。

  4. 对于 Runtime (运行时),选择 Node.js 8.10

  5. 选择 Create function (创建函数)

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

    // 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. exports.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; }
  7. 选择 Save (保存)

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

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

  10. 选择 Authorizers (授权方)

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

  12. 输入授权方的名称。

  13. 对于 Type (类型),选择 Lambda。

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

  15. Lambda Invoke Role (Lambda 调用角色) 留空。

  16. 对于 Lambda Event Payload (Lambda 事件负载),选择 Token (令牌)

  17. 对于 Token Source (令牌来源),输入 tokenHeader

  18. 选择 Test (测试)

  19. 对于 tokenHeader 值,输入 allow

  20. 选择 Test (测试)

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

  • 如果令牌值为 'allow',该授权方函数将返回 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/" } ] }
  • 如果令牌值为 'deny',该授权方函数将返回 403 Forbidden HTTP 响应和 Deny IAM 策略(类似于以下内容)并且方法请求失败:

    { "Version": "2012-10-17", "Statement": [ { "Action": "execute-api:Invoke", "Effect": "Deny", "Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/" } ] }
  • 如果令牌值为 'unauthorized' 或空字符串,该授权方函数将返回 401 Unauthorized HTTP 响应并且方法调用失败。

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

注意

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

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

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

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

  1. 在 Lambda 控制台,选择 Create function (创建函数)

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

  3. 输入函数的名称。

  4. 对于 Runtime (运行时),选择 Node.js 8.10

  5. 选择 Create function (创建函数)

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

    exports.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); }
  7. 选择 Save (保存)

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

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

  10. 选择 Authorizers (授权方)

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

  12. 输入授权方的名称。

  13. 对于 Type (类型),选择 Lambda。

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

  15. Lambda Invoke Role (Lambda 调用角色) 留空。

  16. 对于 Lambda Event Payload (Lambda 事件负载),选择 Request (请求)

  17. Identity Sources (身份来源) 下,添加名为 HeaderAuth1Header (标头)、名为 QueryString1Query String (查询字符串) 和名为 StageVar1Stage Variable (阶段变量)

  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 授权方的输出