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 函数的输出必须是一个包含两个东西的对象:

  1. principalId - 有问题
  2. policyDocument - 一份有效的政策文件,其中包含允许用户授权访问 Lambda 资源、阶段等的声明。

现在,自定义授权者的示例目前显示 principalId 变量几乎是任意值。但是如果我没有想错的话,这个 principalId 对每个用户来说应该是唯一的吧?并且可能具有与之关联的用户特定的唯一值(例如 token.userIdtoken.email)。

如果这是真的,那么对于我在下面提供的代码,如果 JWT 令牌 无效 ,那么我无权访问 userIdemail,并且不知道将 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' 标记的选项。

  1. 如果您 return 拒绝访问的有效策略,这可以通过缓存与令牌关联的策略以防再次使用它来帮助您,从而减少 Lambda 调用。然而,客户端可能会收到 403 并认为令牌有效,但他们无权访问他们请求的资源。

  2. context.fail("Unauthorized") 将向客户端发送一个 401 错误响应,这应该向他们表明令牌无效。这将有助于客户端,但如果客户端反复重放错误令牌,也会导致对该函数的更多调用。负缓存目前在该功能上不可用,但提供适度保护的另一种方法是使用 'identityValidationExpresion' -> http://docs.aws.amazon.com/apigateway/api-reference/resource/authorizer/#identityValidationExpression

此外,我强烈建议您将其迁移到基于 apigateway-authorizer-nodejs 蓝图的新 Lambda 函数,因为文档中的代码示例很少,仅用于说明。蓝图有很多记录各种用途的注释,例如 fail("Unauthorized") 功能。