据我了解,AWS API Gateway 的 AWS Cognito 授权程序会自动验证 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"
}
导致以下参数被传递给 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"
}
值得注意的是,
cognito:groups
参数从字符串数组变为字符串,该字符串用逗号分隔符连接该列表的元素,email_verified
也从布尔值变为字符串,exp
和 iat
日期是现在解析,auth_time
变成一个字符串等
这特别烦人,因为运行依赖于提取这些参数的代码,例如绕过授权方的本地环境或测试比较提供的 jwt 中的值需要考虑这种未记录的行为。
是否有一个包含授权人代码的存储库,我可以在其中提交 PR,或者可能有一种改变这种行为的方法?
更新(24/10/2022):
我找到的唯一相关文档条目是 here 的以下摘录:
在后端Lambda函数的输入中,requestContext对象是键值对的映射。在每一对中,键是 $context 变量属性的名称,值是该属性的值。 API 网关可能会向地图添加新键。
根据启用的功能,requestContext 映射可能因 API 而异。例如,在前面的示例中,未指定授权类型,因此不存在 $context.authorizer.* 或 $context.identity.* 属性。当指定授权类型时,这会导致 API 网关将授权用户信息传递到 requestContext.identity 对象中的集成端点,如下所示:
授权类型为AWS_IAM时,授权用户信息包括$context.identity.*属性。
当授权类型为COGNITO_USER_POOLS(Amazon Cognito authorizer)时,授权用户信息包括$context.identity.cognito*和$context.authorizer.claims.*属性。
当授权类型为CUSTOM(Lambda authorizer)时,授权用户信息包括$context.authorizer.principalId和其他适用的$context.authorizer.*属性。
我想这可能表明
event.contextRequest
仅限于传递具有字符串类型的键值对?
我想我会发表一些相关的想法,就 API 架构应该如何工作的期望行为而言。不过,我超出了你的问题范围。
有用的品质
授权者行为
配置授权器很方便,之后将 JSON 字符串转发到 HTTP 标头中的 lambda。这不是最安全的行为,并且在某些替代设置中可能会被发送恶意标头的人滥用。
零信任行为
一个新兴趋势——主要是在云原生设置中——是每个 API 在每个请求上验证 JWT 访问令牌,而不是网关。这可以防止内部威胁。它还使 lambda 能够接收 JWT 并在 HTTP 请求中将其转发给彼此,以便调用者身份保持可验证。这样做还可以确保在所有环境中都有相同的行为。
LAMBDA 零信任
我的 Serverless API 遵循这种方法,使用 AWS Cognito 访问令牌进行授权,通过避免使用授权方来实现,并在 lambda 本身中完成工作。因此,API 代码可以完全控制声明、错误处理、日志记录等
验证 JWT
执行这个任务的代码其实很简单,只需要几行代码。不幸的是,令牌签名公钥不能在请求之间存储在内存中,这是我的 API 的缺点。它增加了复杂性和性能成本。
总结
如果 lambdas 提供了一个更简单的交叉请求存储选项,我建议避免使用授权方进行 JWT 验证,并在 lambda 本身中完成 JWT 工作。
在您当前的设置中,也许有一个网关策略,例如一个 middy 中间件,它在本地模拟 AWS 授权者,但在 AWS 中什么都不做,可以解决您的问题。