本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
使用 AWS Lambda 授權方控制對 HTTP APIs存取
您可以使用 Lambda 授權方來使用 Lambda 函數,以控制對 HTTP API 的存取權。然後,當用戶端呼叫您的 API 時,API Gateway 會叫用您的 Lambda 函數。API Gateway 會使用 Lambda 函數的回應來判斷用戶端是否可以存取您的 API。
授權方承載格式版本會指定 API Gateway 傳送到 Lambda 授權方的資料格式,以及 API Gateway 如何解釋 Lambda 的回應。如果您未指定承載格式版本, 預設 AWS Management Console 會使用最新版本。如果您使用 AWS CLI AWS CloudFormation或 SDK 建立 Lambda 授權方,則必須指定 authorizerPayloadFormatVersion
。支援的值為 1.0
和 2.0
。
如果您需要與 REST API 相容,請使用 1.0
版。
下列範例顯示每個裝載格式版本的結構。
- 2.0
-
{
"version": "2.0",
"type": "REQUEST",
"routeArn": "arn:aws:execute-api:us-east-1:123456789012:abcdef123/test/GET/request",
"identitySource": ["user1", "123"],
"routeKey": "$default",
"rawPath": "/my/path",
"rawQueryString": "parameter1=value1¶meter1=value2¶meter2=value",
"cookies": ["cookie1", "cookie2"],
"headers": {
"header1": "value1",
"header2": "value2"
},
"queryStringParameters": {
"parameter1": "value1,value2",
"parameter2": "value"
},
"requestContext": {
"accountId": "123456789012",
"apiId": "api-id",
"authentication": {
"clientCert": {
"clientCertPem": "CERT_CONTENT",
"subjectDN": "www.example.com",
"issuerDN": "Example issuer",
"serialNumber": "1",
"validity": {
"notBefore": "May 28 12:30:02 2019 GMT",
"notAfter": "Aug 5 09:36:04 2021 GMT"
}
}
},
"domainName": "id.execute-api.us-east-1.amazonaws.com",
"domainPrefix": "id",
"http": {
"method": "POST",
"path": "/my/path",
"protocol": "HTTP/1.1",
"sourceIp": "IP",
"userAgent": "agent"
},
"requestId": "id",
"routeKey": "$default",
"stage": "$default",
"time": "12/Mar/2020:19:03:58 +0000",
"timeEpoch": 1583348638390
},
"pathParameters": { "parameter1": "value1" },
"stageVariables": { "stageVariable1": "value1", "stageVariable2": "value2" }
}
- 1.0
-
{
"version": "1.0",
"type": "REQUEST",
"methodArn": "arn:aws:execute-api:us-east-1:123456789012:abcdef123/test/GET/request",
"identitySource": "user1,123",
"authorizationToken": "user1,123",
"resource": "/request",
"path": "/request",
"httpMethod": "GET",
"headers": {
"X-AMZ-Date": "20170718T062915Z",
"Accept": "*/*",
"HeaderAuth1": "headerValue1",
"CloudFront-Viewer-Country": "US",
"CloudFront-Forwarded-Proto": "https",
"CloudFront-Is-Tablet-Viewer": "false",
"CloudFront-Is-Mobile-Viewer": "false",
"User-Agent": "..."
},
"queryStringParameters": {
"QueryString1": "queryValue1"
},
"pathParameters": {},
"stageVariables": {
"StageVar1": "stageValue1"
},
"requestContext": {
"path": "/request",
"accountId": "123456789012",
"resourceId": "05c7jb",
"stage": "test",
"requestId": "...",
"identity": {
"apiKey": "...",
"sourceIp": "...",
"clientCert": {
"clientCertPem": "CERT_CONTENT",
"subjectDN": "www.example.com",
"issuerDN": "Example issuer",
"serialNumber": "a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1",
"validity": {
"notBefore": "May 28 12:30:02 2019 GMT",
"notAfter": "Aug 5 09:36:04 2021 GMT"
}
}
},
"resourcePath": "/request",
"httpMethod": "GET",
"apiId": "abcdef123"
}
}
承載格式版本會決定 Lambda 函數必須傳回的回應結構。
格式 1.0 的 Lambda 函數回應
如果您選擇 1.0
格式版本,Lambda 授權方必須傳回允許或拒絕存取 API 路由的 IAM 政策。您可以在政策中使用標準 IAM 政策語法。如需 IAM 政策範例,請參閱控制對 API 的呼叫存取權。您可以使用 $context.authorizer.property
將內容屬性傳遞給 Lambda 整合或存取日誌。context
物件為選擇性,claims
是保留的預留位置,不能用作內容物件。如需進一步了解,請參閱自訂 HTTP API 存取日誌。
{
"principalId": "abcdef", // The principal user identification associated with the token sent by the client.
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Effect": "Allow|Deny",
"Resource": "arn:aws:execute-api:{regionId}:{accountId}:{apiId}/{stage}/{httpVerb}/[{resource}/[{child-resources}]]"
}
]
},
"context": {
"exampleKey": "exampleValue"
}
}
格式 2.0 的 Lambda 函數回應
如果您選擇 2.0
格式版本,則可以從 Lambda 函數傳回布林值或使用標準 IAM 政策語法的 IAM 政策。要傳回一個布林值,請啟用授權方的簡易回應。下列範例會示範您必須編碼 Lambda 函數才能傳回的格式。該 context
物件是選用的物件。您可以使用 $context.authorizer.property
將內容屬性傳遞給 Lambda 整合或存取日誌。如需進一步了解,請參閱自訂 HTTP API 存取日誌。
- Simple response
-
{
"isAuthorized": true/false,
"context": {
"exampleKey": "exampleValue"
}
}
- IAM policy
-
{
"principalId": "abcdef", // The principal user identification associated with the token sent by the client.
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Effect": "Allow|Deny",
"Resource": "arn:aws:execute-api:{regionId}:{accountId}:{apiId}/{stage}/{httpVerb}/[{resource}/[{child-resources}]]"
}
]
},
"context": {
"exampleKey": "exampleValue"
}
}
範例 Lambda 授權方函數
下列範例 Node.js Lambda 函數會示範您需要從 Lambda 函數傳回的 2.0
承載格式版本的必要回應格式。
- Simple response - Node.js
-
export const handler = async(event) => {
let response = {
"isAuthorized": false,
"context": {
"stringKey": "value",
"numberKey": 1,
"booleanKey": true,
"arrayKey": ["value1", "value2"],
"mapKey": {"value1": "value2"}
}
};
if (event.headers.authorization === "secretToken") {
console.log("allowed");
response = {
"isAuthorized": true,
"context": {
"stringKey": "value",
"numberKey": 1,
"booleanKey": true,
"arrayKey": ["value1", "value2"],
"mapKey": {"value1": "value2"}
}
};
}
return response;
};
- Simple response - Python
import json
def lambda_handler(event, context):
response = {
"isAuthorized": False,
"context": {
"stringKey": "value",
"numberKey": 1,
"booleanKey": True,
"arrayKey": ["value1", "value2"],
"mapKey": {"value1": "value2"}
}
}
try:
if (event["headers"]["authorization"] == "secretToken"):
response = {
"isAuthorized": True,
"context": {
"stringKey": "value",
"numberKey": 1,
"booleanKey": True,
"arrayKey": ["value1", "value2"],
"mapKey": {"value1": "value2"}
}
}
print('allowed')
return response
else:
print('denied')
return response
except BaseException:
print('denied')
return response
- IAM policy - Node.js
-
export const handler = async(event) => {
if (event.headers.authorization == "secretToken") {
console.log("allowed");
return {
"principalId": "abcdef", // The principal user identification associated with the token sent by the client.
"policyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Action": "execute-api:Invoke",
"Effect": "Allow",
"Resource": event.routeArn
}]
},
"context": {
"stringKey": "value",
"numberKey": 1,
"booleanKey": true,
"arrayKey": ["value1", "value2"],
"mapKey": { "value1": "value2" }
}
};
}
else {
console.log("denied");
return {
"principalId": "abcdef", // The principal user identification associated with the token sent by the client.
"policyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Action": "execute-api:Invoke",
"Effect": "Deny",
"Resource": event.routeArn
}]
},
"context": {
"stringKey": "value",
"numberKey": 1,
"booleanKey": true,
"arrayKey": ["value1", "value2"],
"mapKey": { "value1": "value2" }
}
};
}
};
- IAM policy - Python
import json
def lambda_handler(event, context):
response = {
# The principal user identification associated with the token sent by
# the client.
"principalId": "abcdef",
"policyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Action": "execute-api:Invoke",
"Effect": "Deny",
"Resource": event["routeArn"]
}]
},
"context": {
"stringKey": "value",
"numberKey": 1,
"booleanKey": True,
"arrayKey": ["value1", "value2"],
"mapKey": {"value1": "value2"}
}
}
try:
if (event["headers"]["authorization"] == "secretToken"):
response = {
# The principal user identification associated with the token
# sent by the client.
"principalId": "abcdef",
"policyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Action": "execute-api:Invoke",
"Effect": "Allow",
"Resource": event["routeArn"]
}]
},
"context": {
"stringKey": "value",
"numberKey": 1,
"booleanKey": True,
"arrayKey": ["value1", "value2"],
"mapKey": {"value1": "value2"}
}
}
print('allowed')
return response
else:
print('denied')
return response
except BaseException:
print('denied')
return response
身分識別來源
您可以選擇性地指定 Lambda 授權方的身分來源。身分來源會指定授權請求所需的資料位置。例如,您可以指定標頭或查詢字串值做為身分來源。如果您指定身分來源,用戶端必須將其包含在請求中。如果用戶端的請求不包含身分來源,則 API Gateway 不會叫用您的 Lambda 授權方,且用戶端會收到 401
錯誤。
下表說明適用於 Lambda 授權方的支援身分來源。
類型 |
範例 |
備註 |
標頭值 |
$request.header.name |
網域名稱需區分大小寫。 |
查詢字串值 |
$request.querystring.name |
查詢字串名稱區分大小寫。 |
環境變數 |
$context.variableName |
支援的內容變數值。 |
階段變數 |
$stageVariables.variableName |
階段變數的值。 |
快取授權方回應
您可藉由指定 authorizerResultTtlInSeconds 來啟用 Lambda 授權方的快取。啟用授權方的快取時,API Gateway 會使用授權方的身分來源做為快取金鑰。如果用戶端在設定的 TTL 內的身分來源中指定相同的參數,則 API Gateway 會使用快取的授權方結果,而不是叫用您的 Lambda 函數。
若要啟用快取,您的授權方必須至少有一個身分來源。
如果您為授權方啟用簡單回應,授權方的回應會完全允許或拒絕符合快取身分來源值的所有 API 請求。如需更精細的許可,請停用簡易回應並傳回 IAM 政策。
預設情況下,API Gateway 會使用快取授權回應 API 的所有路由使用授權。若要快取每個路由的回應,請新增 $context.routeKey
至授權方的身分來源。
建立 Lambda 授權方
當您建立 Lambda 授權方時,您會指定可供 API Gateway 使用的 Lambda 函數。您必須授予 API Gateway 使用 Lambda 函數的資源政策或 IAM 角色叫用該函數的許可。下列 create-authorizer 命令會建立 Lambda 授權方:
aws apigatewayv2 create-authorizer \
--api-id abcdef123
\
--authorizer-type REQUEST \
--identity-source '$request.header.Authorization
' \
--name lambda-authorizer \
--authorizer-uri 'arn:aws:apigateway:us-west-2
:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:my-function
/invocations' \
--authorizer-payload-format-version '2.0
' \
--enable-simple-responses
下列 add-permission 命令會更新 Lambda 函數的資源政策,以授予 API Gateway 叫用函數的許可。如果 API Gateway 沒有叫用函數的許可,用戶端會收到 500 Internal Server Error
。
aws lambda add-permission \
--function-name my-authorizer-function
\
--statement-id apigateway-invoke-permissions-abc123 \
--action lambda:InvokeFunction \
--principal apigateway.amazonaws.com \
--source-arn "arn:aws:execute-api:us-west-2:123456789012:api-id/
authorizers/authorizer-id
"
在您建立了一個授權方並授予 API Gateway 叫用它的許可後,請更新您的路由以使用授權方。下列 update-route 命令會將 Lambda 授權方新增至路由。
aws apigatewayv2 update-route \
--api-id abcdef123
\
--route-id abc123
\
--authorization-type CUSTOM \
--authorizer-id def123
Lambda 授權方疑難排解
如果 API Gateway 無法叫用您的 Lambda 授權方,或者您的 Lambda 授權方傳回無效格式的回應,則用戶端會收到 500 Internal Server
Error
。
若要故障排除錯誤,請啟用 API 階段的存取記錄。在 $context.authorizer.error
記錄格式中包含日誌變數。
如果記錄表示 API Gateway 沒有叫用函數的許可,請更新函數的資源政策或提供 IAM 角色,以授予 API Gateway 叫用授權方的許可。
如果日誌指出您的 Lambda 函數傳回無效的回應,請確認 Lambda 函數傳回所需格式的回應。