API 网关自定义授权方通过 Lambda 的正确主体 ID 值?
Proper Principal ID Value for API Gateway Custom Authorizer via Lambda?
我正在使用带有 Lambda 函数的 API 网关的一项新功能来使用 自定义授权器 (https://docs.aws.amazon.com/apigateway/latest/developerguide/use-custom-authorizer.html)。
授权方使用 JWT 令牌 来验证当前用户上下文和范围的令牌。一切正常,但有一个关于 AWS 策略的概念我无法从文档中完全弄清楚。
Custom Authorizer 函数的输出必须是一个包含两个东西的对象:
principalId
- 有问题
policyDocument
- 一份有效的政策文件,其中包含允许用户授权访问 Lambda 资源、阶段等的声明。
现在,自定义授权者的示例目前显示 principalId
变量几乎是任意值。但是如果我没有想错的话,这个 principalId
对每个用户来说应该是唯一的吧?并且可能具有与之关联的用户特定的唯一值(例如 token.userId
或 token.email
)。
如果这是真的,那么对于我在下面提供的代码,如果 JWT 令牌 无效 ,那么我无权访问 userId
或 email
,并且不知道将 principalId
设置为什么。我暂时将它设置为 user
只是为了让 Deny 策略有一些 return 以确保响应是 403 Forbidden
。
有人知道为 自定义授权方 设置 principalId
的最佳做法吗?
var jwt = require('jsonwebtoken');
var JWT_SECRET = 'My$ecret!';
/**
* Implicit AWS API Gateway Custom Authorizer. Validates the JWT token passed
* into the Authorization header for all requests.
* @param {Object} event [description]
* @param {Object} context [description]
* @return {Object} [description]
*/
exports.handler = function(event, context) {
var token = event.authorizationToken;
try {
var decoded = jwt.verify(token, JWT_SECRET);
context.done(null, generatePolicy(decoded.id, 'Allow', 'arn:aws:execute-api:*:*:*'));
} catch(ex) {
console.error(ex.name + ": " + ex.message);
context.done(null, generatePolicy('user', 'Deny', 'arn:aws:execute-api:*:*:*'));
}
};
function generatePolicy(principalId, effect, 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;
policyDocument.Statement[0] = statementOne;
authResponse.policyDocument = policyDocument;
}
return authResponse;
}
principalId 旨在表示被授权进行 API 调用的任何实体的长期标识符。所以如果你有一个现有的用户数据库,每个用户大概都有一个唯一的标识符或用户名。您提到了 'user',这可能没问题。从功能上讲,如果启用 CloudWatch Logs,principalId 会被记录下来,这也是您可以在映射模板的 $context 中访问的内容。
就您的函数设计而言,您有两种处理 'invalid' 标记的选项。
如果您 return 拒绝访问的有效策略,这可以通过缓存与令牌关联的策略以防再次使用它来帮助您,从而减少 Lambda 调用。然而,客户端可能会收到 403 并认为令牌有效,但他们无权访问他们请求的资源。
context.fail("Unauthorized")
将向客户端发送一个 401 错误响应,这应该向他们表明令牌无效。这将有助于客户端,但如果客户端反复重放错误令牌,也会导致对该函数的更多调用。负缓存目前在该功能上不可用,但提供适度保护的另一种方法是使用 'identityValidationExpresion' -> http://docs.aws.amazon.com/apigateway/api-reference/resource/authorizer/#identityValidationExpression
此外,我强烈建议您将其迁移到基于 apigateway-authorizer-nodejs 蓝图的新 Lambda 函数,因为文档中的代码示例很少,仅用于说明。蓝图有很多记录各种用途的注释,例如 fail("Unauthorized") 功能。
我正在使用带有 Lambda 函数的 API 网关的一项新功能来使用 自定义授权器 (https://docs.aws.amazon.com/apigateway/latest/developerguide/use-custom-authorizer.html)。
授权方使用 JWT 令牌 来验证当前用户上下文和范围的令牌。一切正常,但有一个关于 AWS 策略的概念我无法从文档中完全弄清楚。
Custom Authorizer 函数的输出必须是一个包含两个东西的对象:
principalId
- 有问题policyDocument
- 一份有效的政策文件,其中包含允许用户授权访问 Lambda 资源、阶段等的声明。
现在,自定义授权者的示例目前显示 principalId
变量几乎是任意值。但是如果我没有想错的话,这个 principalId
对每个用户来说应该是唯一的吧?并且可能具有与之关联的用户特定的唯一值(例如 token.userId
或 token.email
)。
如果这是真的,那么对于我在下面提供的代码,如果 JWT 令牌 无效 ,那么我无权访问 userId
或 email
,并且不知道将 principalId
设置为什么。我暂时将它设置为 user
只是为了让 Deny 策略有一些 return 以确保响应是 403 Forbidden
。
有人知道为 自定义授权方 设置 principalId
的最佳做法吗?
var jwt = require('jsonwebtoken');
var JWT_SECRET = 'My$ecret!';
/**
* Implicit AWS API Gateway Custom Authorizer. Validates the JWT token passed
* into the Authorization header for all requests.
* @param {Object} event [description]
* @param {Object} context [description]
* @return {Object} [description]
*/
exports.handler = function(event, context) {
var token = event.authorizationToken;
try {
var decoded = jwt.verify(token, JWT_SECRET);
context.done(null, generatePolicy(decoded.id, 'Allow', 'arn:aws:execute-api:*:*:*'));
} catch(ex) {
console.error(ex.name + ": " + ex.message);
context.done(null, generatePolicy('user', 'Deny', 'arn:aws:execute-api:*:*:*'));
}
};
function generatePolicy(principalId, effect, 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;
policyDocument.Statement[0] = statementOne;
authResponse.policyDocument = policyDocument;
}
return authResponse;
}
principalId 旨在表示被授权进行 API 调用的任何实体的长期标识符。所以如果你有一个现有的用户数据库,每个用户大概都有一个唯一的标识符或用户名。您提到了 'user',这可能没问题。从功能上讲,如果启用 CloudWatch Logs,principalId 会被记录下来,这也是您可以在映射模板的 $context 中访问的内容。
就您的函数设计而言,您有两种处理 'invalid' 标记的选项。
如果您 return 拒绝访问的有效策略,这可以通过缓存与令牌关联的策略以防再次使用它来帮助您,从而减少 Lambda 调用。然而,客户端可能会收到 403 并认为令牌有效,但他们无权访问他们请求的资源。
context.fail("Unauthorized")
将向客户端发送一个 401 错误响应,这应该向他们表明令牌无效。这将有助于客户端,但如果客户端反复重放错误令牌,也会导致对该函数的更多调用。负缓存目前在该功能上不可用,但提供适度保护的另一种方法是使用 'identityValidationExpresion' -> http://docs.aws.amazon.com/apigateway/api-reference/resource/authorizer/#identityValidationExpression
此外,我强烈建议您将其迁移到基于 apigateway-authorizer-nodejs 蓝图的新 Lambda 函数,因为文档中的代码示例很少,仅用于说明。蓝图有很多记录各种用途的注释,例如 fail("Unauthorized") 功能。