You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

同一AWS Cognito用户池多客户端访问令牌互认问题咨询

问题

我正在用Nest.js重构遗留的Django服务,两者均采用AWS Cognito作为身份提供商。尽管使用相同的User Pool ID,但彼此不认可对方生成的访问令牌,导致用户迁移时需要重新登录,不符合需求。我已尝试让两者使用相同Client ID,但问题仍未解决。以下是Nest.js中校验JWT令牌的代码:

export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(
    @Inject(CognitoConfig.KEY)
    cognitoConfig: ConfigType<typeof CognitoConfig>,
    private userRepository: UserRepository,
  ) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      audience: cognitoConfig.appId,
      issuer: cognitoConfig.appAuthority,
      algorithms: ['RS256'],
      secretOrKeyProvider: passportJwtSecret({
        cache: true,
        rateLimit: true,
        jwksRequestsPerMinute: 5,
        jwksUri: cognitoConfig.appAuthority + '/.well-known/jwks.json',
      }),
    });
  }

  // Used internally by Passport
  async validate(payload: any) {
    const user = await this.userRepository.get(payload.email);

    if (!user) {
      throw new NotFoundException('User not found');
    }

    return user;
  }
}

修复方案

1. 统一受众(Audience)校验规则

AWS Cognito访问令牌的aud字段默认是生成该令牌的Client ID。如果Django和Nest.js服务使用不同的Client ID(哪怕同属一个用户池),Nest.js的JWT策略会因aud不匹配拒绝令牌。解决方法:

  • 若需支持多客户端令牌,将audience配置为包含所有允许的Client ID的数组:
    audience: [cognitoConfig.appId, cognitoConfig.djangoClientId],
    
  • 若已使用相同Client ID仍失败,需验证令牌的aud字段和Nest.js配置的audience是否完全一致(注意大小写、特殊字符)。

2. 确保Issuer格式完全一致

Cognito令牌的iss字段格式为https://cognito-idp.<region>.amazonaws.com/<userPoolId>,必须和Nest.js配置的issuer完全匹配,包括末尾是否带斜杠。比如不能一边是https://xxx.com/xxx,另一边是https://xxx.com/xxx/。

3. 校验令牌类型一致性

确认Django和Nest.js使用的是同类型令牌:

  • Cognito的ID令牌(ID Token)主要用于前端身份验证,aud是Client ID;
  • 访问令牌(Access Token)用于资源服务器授权,若配置了资源服务器,aud会是资源服务器的标识符而非Client ID。
    两边必须统一使用访问令牌或ID令牌,且校验逻辑对应正确的令牌类型。

4. 修正JWKS URI拼接问题

检查jwksUri的拼接是否正确,避免多斜杠或路径错误。推荐使用模板字符串拼接减少手动错误:

jwksUri: `${cognitoConfig.appAuthority}/.well-known/jwks.json`,

5. 在Validate方法中补充客户端校验

如果需要更灵活的客户端权限控制,可以在validate方法中直接校验令牌的client_id字段(Cognito访问令牌会包含该字段):

async validate(payload: any) {
  const allowedClientIds = [cognitoConfig.appId, cognitoConfig.djangoClientId];
  if (!allowedClientIds.includes(payload.client_id)) {
    throw new UnauthorizedException('无效客户端');
  }

  const user = await this.userRepository.get(payload.email);
  if (!user) {
    throw new NotFoundException('用户不存在');
  }
  return user;
}

内容的提问来源于stack exchange,提问作者Arif Ata Cengiz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 02:46:29