【问题标题】:Proper Principal ID Value for API Gateway Custom Authorizer via Lambda?通过 Lambda 的 API 网关自定义授权方的正确主体 ID 值?
【发布时间】:2016-05-29 12:48:00
【问题描述】:

我正在使用 API Gateway 的一项新功能和 Lambda 函数来使用 自定义授权者 (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 令牌 not 有效,那么我无权访问 userIdemail,并且没有任何线索将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;
}

【问题讨论】:

    标签: amazon-web-services jwt aws-lambda aws-api-gateway


    【解决方案1】:

    principalId 旨在表示被授权进行 API 调用的任何实体的长期标识符。因此,如果您有一个现有的用户数据库,那么每个用户可能都有一个唯一的标识符或用户名。您提到了“用户”,这可能很好。从功能上讲,如果您启用 CloudWatch Logs,principalId 会被记录,并且也是您可以在 $context 中访问的映射模板。

    就您的功能设计而言,您有两种选择来处理“无效”令牌。

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

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

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

    【讨论】:

    • 谢谢!关于返回的生成策略的 principalId,我仍然有一个澄清问题。让我来看一个场景:1.) 用户登录并拥有一个有效的 JWT 令牌,他们现在可以在每个请求的 Authorization 标头中传递该令牌。 2.) 自定义授权方可以验证令牌并根据解码的 JWT 的有效负载确保授权。 3.) 主体 ID 现在可以类似于:user|1234-abcd-4312-bcdef 这使我能够为该特定用户的所有请求提供唯一标识符。
    • 1.) 用户尚未登录并请求 API 网关上的安全端点。 2.) 自定义授权方尝试验证和解码 JWT,但它是无效/空的。 3.) principalId 现在没有唯一标识符,因为这当然不是尝试访问的有效用户。此处 principalId 值的最佳做法是什么?也许用户|未经授权?我想我的挣扎也是,principalId 对于每个用户来说应该是唯一的吗?还是针对每个用户权限组?对于失败或未经授权的 +Custom Authorizer* 请求,该怎么办?
    • 嗨,Tom,如果客户端根本不发送标头,或者他们以空/null 值发送标头,API Gateway 将立即使用 401 将此请求返回。在令牌无效的情况下,您有两种选择: 1. 如果您希望缓存此无效令牌的结果,“user|Unauthorized”很好,您可以发送 DenyAll 策略。 2.如果你不关心缓存并且希望客户端知道他们的令牌无效,使用 context.fail("Unauthorized") 行,表明客户端应该尝试登录或在某些情况下获取有效令牌在重试之前。
    • 再次,principalId 的功能使用取决于您;如果你想将它传递给你的后端,它可以在映射模板的 $context 中使用。如果您启用 CloudWatch Logs,它也会被记录
    • @JackKohn-AWS 感谢您在这里的出色回答 - 涵盖了我一直在努力解决的问题。我无法在文档中确定地验证这一点......对于失败(“未授权”)功能的声明“负缓存当前不可用”是否仍然有效?
    猜你喜欢
    • 1970-01-01
    • 2019-06-29
    • 2020-02-24
    • 2020-06-17
    • 1970-01-01
    • 2018-01-15
    • 2019-04-19
    • 1970-01-01
    • 2018-12-25
    相关资源
    最近更新 更多