我正在使用带有 Lambda 函数的 API 网关的新功能来使用自定义授权方 (https://docs.aws.amazon.com/apigateway/latest/developerguide/use-custom-authorizer.html)。
授权方使用 JWT 令牌来验证当前用户上下文和范围的令牌。一切正常,但有一个关于 AWS 策略的概念,我无法从文档中完全弄清楚。
自定义授权方函数的输出必须是包含两个内容的对象:
-
principalId
- 有问题 -
policyDocument
- 有效的策略文档,其中包含允许用户授权访问 Lambda 资源、阶段等的语句。
现在,自定义授权方的示例当前显示principalId
变量的几乎任意值。但是,如果我的想法正确,那么这个principalId
对于每个用户来说应该是唯一的吗?并且可能具有与之关联的用户特定唯一值(例如token.userId
或token.email
)。
这是真的,那么对于我在下面提供的代码,如果 JWT 令牌无效,那么我无法访问userId
或email
,并且不知道将principalId
设置为什么。我暂时将其设置为user
只是为了返回拒绝策略以确保响应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 调用的任何实体的长期标识符。因此,如果您有一个现有的用户数据库,则每个用户可能都有一个唯一的标识符或用户名。你提到了"用户",这可能很好。从功能上讲,如果您启用 CloudWatch Logs,则会记录 principalId,并且您也可以在映射模板的$context中访问该 Id。
在函数设计方面,有两个选项来处理"无效"令牌。
-
如果您返回拒绝访问的有效策略,这将通过缓存与令牌关联的策略来帮助您,以防再次使用,从而减少 Lambda 调用。但是,客户端可能会收到 403 并认为令牌有效,但他们无权访问他们请求的资源。
-
context.fail("Unauthorized")
将向客户端发送错误的 401 响应,这应该向他们指示令牌无效。这将对客户端有所帮助,但如果客户端反复重播错误令牌,也会导致对函数的更多调用。负缓存目前在该功能上不可用,但提供中等保护的另一种方法是使用"identityValidationExpresion"-> http://docs.aws.amazon.com/apigateway/api-reference/resource/authorizer/#identityValidationExpression
此外,我强烈建议您将其迁移到基于 apigateway-authorizer-nodejs 蓝图的新 Lambda 函数,因为文档中的代码示例很少,仅用于说明。该蓝图有很多注释,记录了各种用途,例如 fail("未经授权")功能。