Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅
中国的 Amazon Web Services 服务入门
(PDF)。
本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
使用 API Gateway Lambda 授权方
Lambda 授权方(以前称为自定义授权方)是一种 API Gateway 特征,该功能使用 Lambda 函数来控制对 API 的访问。
如果您要实施使用持有者令牌身份验证策略(如 OAuth 或 SAML)或使用请求参数来确定调用方的身份的自定义授权架构,Lambda 授权方将很有用。
当客户端向您的 API 的方法之一发出请求时,API Gateway 将调用您的 Lambda 授权方,从而采用调用方的身份作为输入并返回 IAM 策略作为输出。
Lambda 授权方有两种类型:
-
基于令牌的 Lambda 授权方(又称为 TOKEN
授权方)接收持有者令牌中的调用方身份,如 JSON Web 令牌 (JWT) 或 OAuth 令牌。有关示例应用程序,请参阅巴西开放银行——授权示例 GitHub。
-
基于请求参数 的 Lambda 授权方(又称为 REQUEST
授权方)接收标头、查询字符串参数、stageVariables 和 $context 变量的组合中的调用方身份。
对于 WebSocket API,仅支持基于请求参数的授权器。
可以使用与您创建 API 时不同的 Amazon 账户中的 Amazon Lambda 函数。有关更多信息,请参阅配置跨账户 Lambda 授权方。
例如 Lambda 函数,请参阅上的 aws-apigateway-lambda-authorizer- blueprints。 GitHub
Lambda 授权方身份验证工作流程
下图说明了 Lambda 授权方的授权工作流程。
API Gateway Lambda 授权工作流程
-
客户端对 API Gateway API 方法调用方法,同时传递持有者令牌或请求参数。
-
API Gateway 检查是否为该方法配置了 Lambda 授权方。如果是,API Gateway 调用 Lambda 函数。
-
Lambda 函数通过以下方式对调用方进行身份验证:
-
如果调用成功,Lambda 函数将通过返回一个包含至少一个 IAM 策略和一个委托人标识符的输出对象来授予访问权限。
-
API Gateway 对策略进行评估。
-
如果 Lambda 函数返回响应,则调用可能会失败。401 Unauthorized
您可以自定义401 Unauthorized
网关响应。要了解更多信息,请参阅API Gateway 中的网关响应。
创建 API Gateway Lambda 授权方的步骤
要创建 Lambda 授权方,您需要执行以下任务:
在 Lambda 控制台中创建 API Gateway Lambda 授权方函数
在配置 Lambda 授权方之前,您必须先创建用于实施逻辑以对调用方进行授权和(如有必要)身份验证的 Lambda 函数。Lambda 控制台提供了 Python 蓝图,您可以通过选择使用蓝图并选择蓝图来使用该api-gateway-authorizer-python蓝图。否则,您需要使用 awslabs GitHub 存储库中的一个蓝图作为起点。
对于此部分中的示例 Lambda 授权方函数(未调用其他服务),您可以使用内置的 AWSLambdaBasicExecutionRole
。在为您自己的 API Gateway Lambda 授权方创建 Lambda 函数时,如果该 Lambda 函数调用其他服务,则需要为 Lambda 函数分配一个 IAM 执行角色。 Amazon 要创建该角色,请按照 Amazon Lambda 执行角色中的说明操作。
有关 Lambda 函数的更多示例,请参阅上的 aws-apigateway-lambda-authorizer- blueprints。 GitHub有关示例应用程序,请参阅巴西开放银行——授权示例 GitHub。
示例:创建基于令牌的 Lambda 授权方函数
要创建基于令牌的 Lambda 授权方函数,请在 Lambda 控制台中,对于最新的运行时系统输入以下 Node.js 代码。然后,在 API Gateway 控制台中测试授权方。
创建基于令牌的 Lambda 授权方函数
-
在 Lambda 控制台中,选择创建函数。
-
选择 Author from scratch (从头开始创作)。
-
输入函数的名称。
在运行时中,选择受支持的最新 Node.js 或 Python 运行时。
-
选择创建函数。
-
在编码编辑器中复制/粘贴以下代码。
- Node.js
// 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;
}
- Python
# 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.
import json
def lambda_handler(event, context):
token = event['authorizationToken']
if token == 'allow':
print('authorized')
response = generatePolicy('user', 'Allow', event['methodArn'])
elif token == 'deny':
print('unauthorized')
response = generatePolicy('user', 'Deny', event['methodArn'])
elif token == 'unauthorized':
print('unauthorized')
raise Exception('Unauthorized') # Return a 401 Unauthorized response
return 'unauthorized'
try:
return json.loads(response)
except BaseException:
print('unauthorized')
return 'unauthorized' # Return a 500 error
def generatePolicy(principalId, effect, resource):
authResponse = {}
authResponse['principalId'] = principalId
if (effect and resource):
policyDocument = {}
policyDocument['Version'] = '2012-10-17'
policyDocument['Statement'] = []
statementOne = {}
statementOne['Action'] = 'execute-api:Invoke'
statementOne['Effect'] = effect
statementOne['Resource'] = resource
policyDocument['Statement'] = [statementOne]
authResponse['policyDocument'] = policyDocument
authResponse['context'] = {
"stringKey": "stringval",
"numberKey": 123,
"booleanKey": True
}
authResponse_JSON = json.dumps(authResponse)
return authResponse_JSON
-
选择 Deploy (部署)。
在创建 Lambda 函数后,您需要在 API Gateway 控制台中创建基于令牌的 Lambda 授权方并进行测试。
创建基于令牌的 Lambda 授权方
-
在 API Gateway 控制台中,创建一个简单的 API(如果您还没有这样做)。
-
从 API 列表中选择您的 API。
-
选择 Authorizers (授权方)。
-
选择 Create Authorizer(创建授权方)。
-
在授权方名称中,输入名称。
-
对于授权方类型,选择 Lambda。
-
对于 Lambda 函数,请选择您创建 Lambda 授权方函数 Amazon Web Services 区域 的位置,然后输入函数名称。
-
将 Lambda 调用角色留空。
-
对于 Lambda 事件负载,选择令牌。
-
对于令牌来源,输入 authorizationToken
。
-
选择 Create Authorizer(创建授权方)。
测试授权方
-
选择授权方的名称。
-
在测试授权方下,对于 authorizationToken 值,输入 allow
。
-
选择测试授权方。
在此示例中,当 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'
,授权方函数的测试将返回 200
OK
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/"
}
]
}
在测试环境之外,授权方函数将返回 403 Forbidden
HTTP 响应并且方法请求失败。
-
如果令牌值为 'unauthorized'
或空字符串,授权方函数的测试将返回 401 Unauthorized
HTTP 响应并且方法调用失败。
-
如果令牌为任何其他内容,客户端将收到 500 Invalid token
响应并且方法调用失败。
在生产代码中,您可能需要先对用户进行身份验证,然后才能授予授权。如果这样,您也可以通过调用身份验证提供商(如该提供商的文档中的指示)在 Lambda 函数中添加身份验证逻辑。
除了返回 IAM 策略之外,Lambda 授权方函数还必须返回调用方的委托人标识符。它还可以选择返回一个 context
对象(包含可传入集成后端的其他信息)。有关更多信息,请参阅来自 Amazon API Gateway Lambda 授权方的输出。
示例:创建基于请求的 Lambda 授权方函数
要创建基于请求的 Lambda 授权方函数,请在 Lambda 控制台中,对于最新的运行时系统输入以下 Node.js 代码。然后,在 API Gateway 控制台中测试授权方。
-
在 Lambda 控制台中,选择创建函数。
-
选择 Author from scratch (从头开始创作)。
-
输入函数的名称。
在运行时中,选择受支持的最新 Node.js 或 Python 运行时。
-
选择创建函数。
-
在编码编辑器中复制/粘贴以下代码。
- Node.js
-
// 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.
export const handler = function(event, context, callback) {
console.log('Received event:', JSON.stringify(event, null, 2));
// 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);
}
- Python
# 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.
import json
def lambda_handler(event, context):
print(event)
# Retrieve request parameters from the Lambda function input:
headers = event['headers']
queryStringParameters = event['queryStringParameters']
pathParameters = event['pathParameters']
stageVariables = event['stageVariables']
# Parse the input for the parameter values
tmp = event['methodArn'].split(':')
apiGatewayArnTmp = tmp[5].split('/')
awsAccountId = tmp[4]
region = tmp[3]
restApiId = apiGatewayArnTmp[0]
stage = apiGatewayArnTmp[1]
method = apiGatewayArnTmp[2]
resource = '/'
if (apiGatewayArnTmp[3]):
resource += apiGatewayArnTmp[3]
# Perform authorization to return the Allow policy for correct parameters
# and the 'Unauthorized' error, otherwise.
authResponse = {}
condition = {}
condition['IpAddress'] = {}
if (headers['headerauth1'] == "headerValue1" and queryStringParameters["QueryString1"]
== "queryValue1" and stageVariables["StageVal1"] == "stageValue1"):
response = generateAllow('me', event['methodArn'])
print('authorized')
return json.loads(response)
else:
print('unauthorized')
raise Exception('Unauthorized') # Return a 401 Unauthorized response
return 'unauthorized'
# Help function to generate IAM policy
def generatePolicy(principalId, effect, resource):
authResponse = {}
authResponse['principalId'] = principalId
if (effect and resource):
policyDocument = {}
policyDocument['Version'] = '2012-10-17'
policyDocument['Statement'] = []
statementOne = {}
statementOne['Action'] = 'execute-api:Invoke'
statementOne['Effect'] = effect
statementOne['Resource'] = resource
policyDocument['Statement'] = [statementOne]
authResponse['policyDocument'] = policyDocument
authResponse['context'] = {
"stringKey": "stringval",
"numberKey": 123,
"booleanKey": True
}
authResponse_JSON = json.dumps(authResponse)
return authResponse_JSON
def generateAllow(principalId, resource):
return generatePolicy(principalId, 'Allow', resource)
def generateDeny(principalId, resource):
return generatePolicy(principalId, 'Deny', resource)
-
选择 Deploy (部署)。
在创建 Lambda 函数后,您需要在 API Gateway 控制台中创建基于请求的 Lambda 授权方并进行测试。
创建基于请求的 Lambda 授权方
-
在 API Gateway 控制台中,创建一个简单的 API(如果您还没有这样做)。
-
从 API 列表中选择您的 API。
-
选择 Authorizers (授权方)。
-
选择 Create Authorizer(创建授权方)。
-
在授权方名称中,输入名称。
-
对于授权方类型,选择 Lambda。
-
对于 Lambda 函数,请选择您创建 Lambda 授权方函数 Amazon Web Services 区域 的位置,然后输入函数名称。
-
将 Lambda 调用角色留空。
-
对于 Lambda 事件负载,选择请求。
-
在身份源类型下,输入以下内容:
-
选择标头并输入 headerauth1
,然后选择添加参数。
-
在身份源类型下,选择查询字符串并输入 QueryString1
,然后选择添加参数。
-
在身份源类型下,选择阶段变量并输入 StageVar1
。
-
选择 Create Authorizer(创建授权方)。
测试授权方
-
选择授权方的名称。
-
在测试授权方下,输入以下内容:
-
选择标头并输入 headerValue1
,然后选择添加参数。
-
在身份源类型下,选择查询字符串并输入 queryValue1
,然后选择添加参数。
-
在身份源类型下,选择阶段变量并输入 stageValue1
。
-
选择测试授权方。
在此示例中,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 授权方的输出。