本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
使用 API Gateway Lambda 授權方
使用 Lambda 授權者 (以前稱為自訂授權者) 來控制 API 的存取權。當用戶端向您的 API 方法提出要求時,API Gateway 會呼叫您的 Lambda 授權者。Lambda 授權者會將呼叫者的身分識別視為輸入,並傳回 IAM 政策做為輸出。
使用 Lambda 授權器實作自訂授權配置。您的配置可以使用請求參數來確定調用者的身份,或者使用承載令牌身份驗證策略,例如 OAuth 或 SAML。使用或 AWS 開發套件,在 API Gateway REST API 主控台中建立 Lambda 授權者。 AWS CLI
授 Lambda 者授權工作流程
下圖顯示 Lambda 授權者的授權工作流程。
API Gateway Lambda 授權工作流程
-
客戶端調用 API Gateway 上的方法,傳遞承載令牌或請求參數。
-
API Gateway 會檢查方法請求是否已使用 Lambda 授權器進行設定。如果已設定,API Gateway 將會呼叫 Lambda 函式。
-
Lambda 函數會驗證呼叫者。該函數可以通過以下方式進行身份驗證:
-
Lambda 函數會傳回 IAM 政策和主要識別碼。如果 Lambda 函數未傳回該資訊,則呼叫會失敗。
-
API Gateway 會評估 IAM 政策。
-
如果拒絕存取,API Gateway 會傳回一個適當的 HTTP 狀態碼,例如 403
ACCESS_DENIED
。
-
如果允許存取,API Gateway 會叫用該方法。
如果您啟用授權快取,API Gateway 會快取原則,以便不再叫用 Lambda 授權者函數。
您可以自訂403
ACCESS_DENIED
或401 UNAUTHORIZED
閘道回應。如需進一步了解,請參閱API Gateway 中 REST API 的閘道回應。
選擇一種 Lambda 授權者類型
Lambda 授權方有兩種類型:
- 請求以參數為基礎的 Lambda 授權者 (授權者)
REQUEST
-
REQUEST
授權者會以標頭、查詢字串參數和$context變數的組合接收呼叫者的身分。stageVariables您可以使用REQUEST
授權者根據來自多個身分識別來源 (例如$context.path
和上下$context.httpMethod
文變數) 的資訊來建立精細的原則。
如果您為授權REQUEST
者開啟授權快取,API Gateway 會驗證要求中是否存在所有指定的身分識別來源。如果指定的識別來源遺失、空值或空白,API Gateway 會傳回 401 Unauthorized
HTTP 回應,而不呼叫 Lambda 授權者函數。定義多個身分識別來源時,它們都會用來衍生授權者的快取金鑰,並保留順序。您可以使用多個身分識別來源來定義精細的快取金鑰。
如果您變更任何快取金鑰部分,並重新部署 API,授權者會捨棄快取的政策文件並產生新的原則文件。
如果您關閉授權REQUEST
者的授權快取,API Gateway 會直接將請求傳遞給 Lambda 函數。
- 基於令牌的 Lambda 授權者(授權者)
TOKEN
-
TOKEN
授權者在承載令牌中接收呼叫者的身份,例如 JSON Web 令牌(JWT)或 OAuth 令牌。
如果您開啟授權TOKEN
者的授權快取,在權杖來源中指定的標頭名稱會成為快取金鑰。
此外,您可以使用權杖驗證來輸入 RegEx 陳述式。API Gateway 會針對此運算式執行輸入權杖的初始驗證,並在成功驗證後叫用 Lambda 授權者函數。這樣做有助於減少對 API 的呼叫。
該IdentityValidationExpression
屬性僅支持TOKEN
授權者。如需詳細資訊,請參閱 x-amazon-apigateway-authorizer 物件。
我們建議您使用REQUEST
授權者來控制 API 的存取權。在使用授權者時,您可以根據多個身分識別來源控制 API 的存取,與使用REQUEST
授權者時的單一身分識別來源相比。TOKEN
此外,您可以使用REQUEST
授權者的多個身分識別來源來分隔快取金鑰。
範例REQUEST
授權者 Lambda 函數
下列範例程式碼會建立 Lambda 授權者函數,如果用戶端提供的HeaderAuth1
標頭、QueryString1
查詢參數和 stage 變數StageVar1
分別符合指定的、和stageValue1
值 headerValue1
queryValue1
,則允許請求。
- 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['StageVar1'] == "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)
在此範例中,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 響應,並且該方法請求失敗。
除了傳回 IAM 政策,Lambda 授權方函數還必須傳回發起人的主要識別符。或者,它可以返回一個包context
含可傳遞到集成後端的其他信息的對象。如需詳細資訊,請參閱 來自 API Gateway Lambda 授權者的輸出。
在生產代碼中,您可能需要在授予授權之前對用戶進行身份驗證。您可以依照該提供者的說明文件中的指示呼叫驗證提供者,在 Lambda 函數中新增驗證邏輯。
範例TOKEN
授權者 Lambda 函數
下列範例程式碼會建立 TOKEN
Lambda 授權者函數,如果用戶端提供的 Token 值為,可讓呼叫者叫用方法。allow
如果令牌值是,則不允許調用者調用請求deny
。如果令牌值unauthorized
或空字符串,則授權者函數返回401 UNAUTHORIZED
響應。
- 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
在此範例中,當 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/"
}
]
}
在測試環境之外,API Gateway 會傳回 403 Forbidden
HTTP 回應,且方法要求失敗。
-
如果符記值為 unauthorized
或空字串,授權方函數會傳回 401 Unauthorized
HTTP 回應,而且方法呼叫會失敗。
-
如果符記為其他值,用戶端會收到 500 Invalid token
回應,而且方法呼叫會失敗。
除了傳回 IAM 政策,Lambda 授權方函數還必須傳回發起人的主要識別符。或者,它可以返回一個包context
含可傳遞到集成後端的其他信息的對象。如需詳細資訊,請參閱 來自 API Gateway Lambda 授權者的輸出。
在生產代碼中,您可能需要在授予授權之前對用戶進行身份驗證。您可以依照該提供者的說明文件中的指示呼叫驗證提供者,在 Lambda 函數中新增驗證邏輯。
Lambda 授權者函數的其他範例
下列清單顯示 Lambda 授權者函數的其他範例。您可以在建立 API 的相同帳戶或不同帳戶中建立 Lambda 函數。
對於前面的 Lambda 函數範例,您可以使用內建函數 AWSLambdaBasicExecutionRole,因為這些函數不會呼叫其他 AWS 服務。如果您的 Lambda 函數呼叫其他 AWS 服務,則需要將 IAM 執行角色指派給 Lambda 函數。若要建立角色,請依照 AWS Lambda 執行角色中的指示。
Lambda 授權者函數的其他範例
-
有關示例應用程序,請參閱巴西開放銀行-授權樣本 GitHub。
-
有關 Lambda 函數的更多示例,請參閱 aws-apigateway-lambda-authorizer。 GitHub
-
您可以建立 Lambda 授權器,使用 Amazon Cognito 使用者集區對使用者進行身份驗證,並使用已驗證許可根據政策存放區授權來電者。如需詳細資訊,請參閱 Amazon 驗證許可使用者指南中的使用連線 API 和身分提供者建立政策存放區。
-
Lambda 主控台提供 Python 藍圖,您可以選擇使用藍圖並選擇藍圖來使用該api-gateway-authorizer-python藍圖。