我的 API Gateway 代理資源具有已啟用快取的 Lambda 授權方,為何傳回 HTTP 403「使用者無權存取此資源」錯誤?
我的 Amazon API Gateway 代理資源具有已啟用快取的 AWS Lambda 授權方,會傳回以下 HTTP 403 錯誤訊息:"User is not authorized to access this resource (使用者無權存取此資源)"。為什麼會發生這種情況?我該如何解決這個錯誤?
簡短描述
注意: API Gateway 可能會因多種原因而傳回 403 錯誤使用者無權存取此資源。本文解決了與具有已啟用快取的 Lambda 授權方的 API Gateway 代理資源相關的 403 錯誤。如需對其他類型的 403 錯誤進行疑難排解,請參閲如何針對 API Gateway 的 HTTP 403 錯誤進行疑難排解?
Lambda 授權方的輸出會將 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 授權方上啟用授權快取時,將快取傳回的 IAM 政策。然後,快取 IAM 政策將套用於在快取指定的存留時間 (TTL) 期間內發出的任何額外 API 請求。
如果 API 具有包含 {proxy+} 窮盡 (greedy) 路徑變數的代理資源,則第一個授權會成功。在快取 TTL 週期內對不同路徑發出的任何額外 API 請求均會失敗,並傳回以下錯誤:
"message":「使用者無權存取此資源」
額外請求失敗,因為路徑與快取的 IAM 政策中所定義的明確 API Gateway API "Resource" 元素不相符。
若要解決此問題,您可以修改 Lambda 授權方函數的程式碼,改為在輸出中傳回萬用字元 (*/*) 資源。如需詳細資訊,請參閱 Lambda 動作的資源和條件。
附註:若要啟用授權者快取,您的授權者必須傳回對於整個 API Gateway 的所有方法適用的政策。Lambda 授權者函數的程式碼必須在輸出中傳回萬用字元 (*/*) 資源,才能允許所有資源。快取政策會預期快取相同的資源路徑,除非您在相同的資源路徑上發出兩次相同的要求。
解決方案
注意: 修改本文中的範例 Lambda 授權方函數程式碼片段以配合您的使用案例。
在以下範例設定中,Lambda 函數從方法的 Amazon 資源名稱 (ARN) ("event.methodArn") 中擷取 API Gateway 的 ID 值。然後,函數會將方法 ARN 的路徑與 API 的 id 值和萬用字元 (*/*) 結合,來定義萬用字元 "Resource" 變數。
以字符為基礎且傳回萬用字元 "Resource" 變數的 Lambda 授權方函數程式碼範例
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 授權方函數程式碼範例
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 函數。
相關資訊
相關內容
- 已提問 9 個月前lg...
- 已提問 14 天前lg...
- AWS 官方已更新 2 年前
- AWS 官方已更新 2 年前