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

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

使用 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 Lambda 授權工作流程
  1. 客戶端調用 API Gateway 上的方法,傳遞承載令牌或請求參數。

  2. API Gateway 會檢查方法請求是否已使用 Lambda 授權器進行設定。如果已設定,API Gateway 將會呼叫 Lambda 函式。

  3. Lambda 函數會驗證呼叫者。該函數可以通過以下方式進行身份驗證:

    • 通過調用 OAuth 提供程序以獲取 OAuth 訪問令牌。

    • 呼叫 SAML 提供者以取得 SAML 宣告。

    • 根據請求參數值產生 IAM 政策。

    • 從資料庫擷取認證。

  4. Lambda 函數會傳回 IAM 政策和主要識別碼。如果 Lambda 函數未傳回該資訊,則呼叫會失敗。

  5. API Gateway 會評估 IAM 政策。

    • 如果拒絕存取,API Gateway 會傳回一個適當的 HTTP 狀態碼,例如 403 ACCESS_DENIED

    • 如果允許存取,API Gateway 會叫用該方法。

      如果您啟用授權快取,API Gateway 會快取原則,以便不再叫用 Lambda 授權者函數。

您可以自訂403 ACCESS_DENIED401 UNAUTHORIZED閘道回應。如需進一步了解,請參閱API Gateway 中的閘道回應

選擇一種 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分別符合指定的、和stageValue1headerValue1queryValue1,則允許請求。

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藍圖。