为什么 AWS API Gateway Cognito Authroizer 更改提取的声明中的 JWT 负载?

Mar*_*Wac 5 amazon-web-services jwt amazon-cognito aws-api-gateway

据我了解,AWS API Gateway 的 AWS Cognito Authorizer 会自动验证 JWT 并解析有效负载,并在传递给 lambda 集成的参数event.requestContext.authorizer.claims部分中包含一些声明event

这很方便,因为这意味着我不必从 JWT 手动提取数据,但cognito:groups在此过程中某些声明(尤其是 )的格式会发生变化。

例如,以下 JWT 负载:

{
  "sub": "xxx",
  "cognito:groups": [
    "group-a",
    "group-b"
  ],
  "email_verified": true,
  "iss": "https://cognito-idp.eu-west-1.amazonaws.com/xxx",
  "cognito:username": "xxx",
  "given_name": "xxx",
  "origin_jti": "xxx",
  "aud": "xxx",
  "event_id": "xxx",
  "token_use": "id",
  "auth_time": 1666606318,
  "exp": 1666692718,
  "iat": 1666606318,
  "family_name": "xxx",
  "jti": "xxx",
  "email": "xxx"
}
Run Code Online (Sandbox Code Playgroud)

结果以下参数被传递给 lambda event.requestContext.authorizer.claims

{
  "sub": "xxx",
  "cognito:groups": "group-a,group-b",
  "email_verified": "true",
  "iss": "https://cognito-idp.eu-west-1.amazonaws.com/xxx",
  "cognito:username": "xxx",
  "given_name": "xxx",
  "origin_jti": "xxx",
  "aud": "xxx",
  "event_id": "xxx",
  "token_use": "id",
  "auth_time": "1666606318",
  "exp": "Tue Oct 25 10:11:58 UTC 2022",
  "iat": "Mon Oct 24 10:11:58 UTC 2022",
  "family_name": "xxx",
  "jti": "xxx",
  "email": "xxx"
}
Run Code Online (Sandbox Code Playgroud)

值得注意的是,cognito:groups参数从字符串数组更改为用逗号分隔符连接该列表的元素的字符串,email_verified也从布尔值更改为字符串,expiat日期现在被解析,auth_time成为字符串等。

这尤其令人烦恼,因为运行依赖于这些参数提取的代码(例如绕过授权者的本地环境或测试比较提供的 jwt 中的值)需要考虑这种未记录的行为。

是否有一个包含授权者代码的存储库,我可以在其中提交 PR,或者可能是改变这种行为的方法?


更新(2022 年 10 月 24 日):

我找到的唯一相关文档条目是这里的以下摘录

在后端 Lambda 函数的输入中,requestContext 对象是键值对的映射。在每一对中,键是 $context 变量属性的名称,值是该属性的值。API网关可能会向地图添加新的键。

根据启用的功能,requestContext 映射可能因 API 而异。例如,在前面的示例中,未指定授权类型,因此不存在 $context.authorizer.* 或 $context.identity.* 属性。指定授权类型后,这会导致 API Gateway 将授权用户信息传递到 requestContext.identity 对象中的集成终端节点,如下所示:

当授权类型为AWS_IAM时,授权用户信息包含$context.identity.*属性。

当授权类型为 COGNITO_USER_POOLS(Amazon Cognito 授权方)时,授权用户信息包括 $context.identity.cognito* 和 $context.authorizer.claims.* 属性。

当授权类型为 CUSTOM(Lambda 授权者)时,授权用户信息包括 $context.authorizer.principalId 和其他适用的 $context.authorizer.* 属性。

我想这可能表明event.contextRequest仅限于传递具有字符串类型的键值对?

Gar*_*her 1

我想就 API 架构如何工作的期望行为发表一些相关的想法。不过,我超出了你的问题范围。

有用的品质

  • API 调用在开发计算机上的工作方式与在云中的工作方式相同
  • API 可以相互转发 JWT 访问令牌,以可验证的方式传递用户身份
  • 您可以控制 JWT 错误处理、日志记录和审核

授权者行为

配置授权者很方便,之后将 JSON 字符串转发到 HTTP 标头中的 lambda。这不是最安全的行为,并且在某些替代设置中可能会被发送恶意标头的人滥用。

零信任行为

一个新兴趋势(主要是在云原生设置中)是每个 API 在每个请求上验证 JWT 访问令牌,而不是网关。这可以防止内部威胁。它还使 lambda 能够接收 JWT 并在 HTTP 请求中将其转发给彼此,以便调用者身份保持可验证。这样做还可以确保在所有环境中都有相同的行为。

Lambda 零信任

我的无服务器 API遵循这种方法,通过避免使用授权者并在 lambda 本身中完成工作来授权使用 AWS Cognito 访问令牌。因此,API 代码可以完全控制声明、错误处理、日志记录等。

验证 JWT

执行此任务的代码实际上很简单,只需要几行代码。不幸的是,令牌签名公钥无法在请求之间存储在内存中,这是我的 API 的缺点。它增加了复杂性和性能成本,尽管我尽我所能减轻它。

概括

如果 lambda 提供了更简单的交叉请求存储选项,我建议避免使用授权者进行 JWT 验证,并在 lambda 本身中执行 JWT 工作。

在您当前的设置中,也许lambda 中间件类是解决您的问题的最简单的选择。在 AWS 中,这可以在 thd lambda 的主代码执行之前将声明转换回 JWT 格式,并且在本地测试设置中不执行任何操作。