Help us improve the AWS re:Post Knowledge Center by sharing your feedback in a brief survey. Your input can influence how we create and update our content to better support your AWS journey.
為什麼我的 API Gateway Proxy 資源 (具有已啟動快取的 Lambda Authorizer) 會傳回 HTTP 403「使用者未獲得存取此資源的授權」錯誤?
具有已啟動快取之 AWS Lambda Authorizer 的 Amazon API Gateway Proxy 資源會傳回下列 HTTP 403 錯誤訊息: 「使用者未獲得存取此資源的授權」。
簡短描述
**注意:**API Gateway 可能會因為各種原因而傳回 403 **「使用者未獲得存取此資源的授權」**錯誤。本文將解說與 API Gateway Proxy 資源 (具有僅啟用快取的 Lambda Authorizer) 相關的 403 錯誤。如需有關對其他 403 錯誤類型進行疑難排解的資訊,請參閱如何對 API Gateway 的 HTTP 403 錯誤進行疑難排解?
Lambda Authorizer 的輸出會將 AWS Identity and Access Management (IAM) 政策傳回 API Gateway。IAM 政策包含採用下列格式的明確 API Gateway API "Resource"元素:
"arn:aws:execute-api:<region>:<account>:<API_id>/<stage>/<http-method>/[<resource-path-name>/[<child-resources-path>]"
在 Lambda Authorizer 上啟用授權快取時,傳回的 IAM 政策會受到快取。然後,受到快取的 IAM 政策會套用至快取指定存留時間 (TTL) 期間內所發出的任何其他 API 請求。
如果 API 有一個具有窮盡路徑變數為 {proxy+} 的 Proxy 資源,則第一個授權將成功。在快取的 TTL 期間內對其他路徑發出的任何其他 API 請求都會失敗,並傳回下列錯誤:
「訊息」: 「使用者未獲得存取此資源的授權」
因為路徑不符合受到快取之 IAM 政策中定義的明確 API Gateway API "Resource" 元素,所以其他請求失敗。
若要解決此問題,您可以修改 Lambda Authorizer 的程式碼,改為在輸出中傳回萬用字元 (*/*) 資源。如需詳細資訊,請參閱 Lambda 動作的資源與條件。
注意: 若要啟動 Authorizer 快取,您的 Authorizer 必須傳回適用於 API Gateway 中所有方法的政策。Lambda Authorizer 函數的程式碼必須在輸出中傳回萬用字元 (*/*) 資源,才能允許所有資源。除非您在相同的資源路徑上提出兩次相同的請求,否則快取政策預期會快取相同的資源路徑。
解決方法
**注意:**請修改本文中的範例 Lambda Authorizer 函數程式碼片段,以符合您的使用案例。
在下列範例設定中,Lambda 函數從方法的 Amazon Resource Name (ARN) ("event.methodArn") 中擷取 API Gateway 的 ID 值。然後,函數透過將方法 ARN 的路徑與 API 的 id 值和萬用字元 (*/*) 結合,以定義萬用字元 "Resource" 變數。
傳回萬用字元 "Resource" 變數的範例權杖型 Lambda Authorizer 函數程式碼
exports.handler = function(event, context, callback) { var token = event.authorizationToken; var tmp = event.methodArn.split(':'); var apiGatewayArnTmp = tmp[5].split('/'); // Create wildcard resource var resource = tmp[0] + ":" + tmp[1] + ":" + tmp[2] + ":" + tmp[3] + ":" + tmp[4] + ":" + apiGatewayArnTmp[0] + '/*/*'; switch (token) { case 'allow': callback(null, generatePolicy('user', 'Allow', resource)); break; case 'deny': callback(null, generatePolicy('user', 'Deny', resource)); 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; }
傳回萬用字元 "Resource" 變數的範例請求參數型 Lambda Authorizer 函數程式碼
exports.handler = function(event, context, callback) { // 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('/'); // Create wildcard resource var resource = tmp[0] + ":" + tmp[1] + ":" + tmp[2] + ":" + tmp[3] + ":" + tmp[4] + ":" + apiGatewayArnTmp[0] + '/*/*'; console.log("resource: " + 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', resource)); } else { callback("Unauthorized"); } } // Help function to generate an IAM policy var generatePolicy = function(principalId, effect, resource) { // Required output: console.log("Resource in generatePolicy(): " + resource); 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; console.log("***Resource*** " + resource); policyDocument.Statement[0] = statementOne; console.log("***Generated Policy*** "); console.log(policyDocument); 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); }
如需如何編輯 Lambda 函數程式碼的詳細資訊,請參閱部署定義為 .zip 檔案存檔的 Lambda 函數。
