Go语言Lambda搭配API Gateway与Cognito认证时CognitoIdentityID为空如何识别客户端
我在API Gateway后方部署了Go语言编写的AWS Lambda函数,认证方案采用Cognito应用集成搭配OAuth客户端凭证授权模式。我需要在Lambda函数内部识别发起请求的应用客户端,但上下文与请求对象中所有Cognito相关字段(CognitoIdentityID、CognitoIndetityPoolID、AccountID等)均为空值,仅能在请求头中查看到Bearer类型的Authorization认证信息。我使用如下代码打印相关字段值:
var forwardRequest = func(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { println(fmt.Sprintf("Request arrived: Stage: %s, Method: %s, Path: %s", request.RequestContext.Stage, request.HTTPMethod, request.Path)) lc, _ := lambdacontext.FromContext(ctx) println(fmt.Sprintf("lc: %+v", lc)) println(fmt.Sprintf("request: %+v", request)) ... } func main() { // Make the handler available for Remote Procedure Call by AWS Lambda lambda.Start(forwardRequest) }
我已经参照同类问题的解决方案启用了Lambda Proxy integration(Lambda代理集成),当前无法启用“Invoke with caller credentials(使用调用方凭证调用)”选项,请问如何才能识别发起请求的客户端?
先理清几个容易混淆的Cognito和API Gateway配置逻辑,你遇到的空值、选项灰化都不是配置错误:
CognitoIdentityID、CognitoIdentityPoolID这几个字段,仅在使用Cognito联邦身份池(Identity Pool)做鉴权、且开启调用方凭证传递时才会被填充。你当前用的是Cognito用户池(User Pool)的OAuth客户端凭证授权模式,这些字段天生为空。- “Invoke with caller credentials(使用调用方凭证调用)”选项仅对IAM类型的授权器生效,Cognito用户池授权器场景下该选项默认不可勾选,是产品的正常设计。
不需要调整现有Lambda代理集成配置,两种方式可以稳定拿到发起请求的Cognito应用客户端ID:
方案1:从API Gateway透传的授权上下文直接取值(推荐,无需自行验签)
Lambda代理集成模式下,Cognito用户池授权器完成令牌合法性校验后,会把解析完成的JWT全量声明塞到请求上下文的Authorizer字段里。你之前打印全量request对象没拿到对应值,是因为Go SDK里这个字段默认是map[string]interface{}类型,client_id不会作为请求上下文的顶层字段暴露。
直接用如下代码读取即可:
// 提取Cognito授权器解析完成的JWT声明 claims, ok := request.RequestContext.Authorizer["claims"].(map[string]interface{}) if !ok { return events.APIGatewayProxyResponse{StatusCode: 500}, fmt.Errorf("authorizer claims missing") } // JWT中的client_id字段就是发起请求的应用客户端ID clientID, ok := claims["client_id"].(string) if !ok { return events.APIGatewayProxyResponse{StatusCode: 400}, fmt.Errorf("client_id not found in access token") } // 拿到clientID后直接做后续业务逻辑即可
补充:如果你用的是API Gateway HTTP API版本,JWT声明的存放路径为
request.RequestContext.Authorizer["jwt"].(map[string]interface{})["claims"],核心取值逻辑一致。
方案2:自行解析Authorization头中的JWT令牌
如果需要做令牌二次校验、或者兼容多套API Gateway配置,可以直接从请求头提取Bearer令牌,本地验签后解析client_id:
- 第一步:从
request.Headers["Authorization"]值中去掉Bearer前缀,拿到原始JWT字符串 - 第二步:拉取对应Cognito用户池的公开JWKS公钥(本地缓存即可,不需要每次请求拉取),校验JWT的签名、过期时间、签发方、受众等合法性
- 第三步:解析JWT payload,其中的
client_id字段就是调用方对应的应用客户端ID
Go生态直接用github.com/golang-jwt/jwt/v5搭配Cognito公开的JWKS端点就能实现,不需要额外依赖AWS服务SDK。
- 确认API Gateway对应方法已经正确绑定了目标Cognito用户池的授权器,授权器的令牌源配置为
Authorization头,令牌校验规则匹配你使用的用户池 - 客户端凭证流签发的JWT不会携带用户相关的
sub/username字段,所有调用方标识都存放在client_id、scope字段中,不要尝试读取用户维度字段,必然拿到空值。
内容的提问来源于stack exchange,提问作者Ivan Martinez

