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

NestJS集成JWT时req.user始终返回同一用户的问题

NestJS JWT切换用户后req.user不变的解决方案

核心排查方向及修复方案

1. 移除JWT策略中的用户缓存逻辑

如果你的JwtStrategy里用了全局变量缓存用户,会导致所有验证请求都返回第一个缓存的用户。

错误示例:

// 全局变量缓存用户,导致用户不更新
let cachedUser: User;

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(private readonly usersService: UsersService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      secretOrKey: process.env.JWT_SECRET,
    });
  }

  async validate(payload: any) {
    if (!cachedUser) {
      cachedUser = await this.usersService.findOne(payload.sub);
    }
    return cachedUser;
  }
}

修复代码:

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(private readonly usersService: UsersService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      secretOrKey: process.env.JWT_SECRET,
    });
  }

  async validate(payload: any) {
    // 每次验证都重新查询当前用户
    const user = await this.usersService.findOne(payload.sub);
    if (!user) throw new UnauthorizedException();
    return user;
  }
}

2. 检查客户端是否更新了JWT令牌

切换用户时,客户端必须替换请求头中的Authorization: Bearer <token>为新用户的令牌。如果客户端没更新,后端会一直解析旧令牌返回旧用户。

后端验证方式:在控制器中临时添加调试代码,确认请求令牌是否正确:

@Get('/profile')
@UseGuards(JwtAuthGuard)
getProfile(@Req() req) {
  console.log('当前请求令牌:', req.headers.authorization?.split(' ')[1]);
  return req.user;
}

3. 修正JWT签发时的用户标识

如果签发JWT时硬编码了用户ID,所有令牌解析后都会指向同一个用户。

错误示例:

async login(@Body() loginDto: LoginDto) {
  const user = await this.usersService.validateUser(loginDto);
  // 硬编码用户ID,导致所有令牌的sub都是1
  const payload = { username: user.username, sub: 1 };
  return { access_token: this.jwtService.sign(payload) };
}

修复代码:

async login(@Body() loginDto: LoginDto) {
  const user = await this.usersService.validateUser(loginDto);
  // 使用当前用户的真实ID作为唯一标识
  const payload = { username: user.username, sub: user.id };
  return { access_token: this.jwtService.sign(payload) };
}

4. 排查全局拦截器/守卫的缓存逻辑

检查全局拦截器或守卫是否存在缓存req.user的逻辑(比如用全局变量存储用户数据),确保所有用户信息处理都基于当前请求对象,不共享全局状态。

5. 确认Passport模块配置正确性

确保JwtModule是全局模块或在需要的模块中正确导入,避免多实例导致的上下文冲突:

@Module({
  imports: [
    JwtModule.register({
      secret: process.env.JWT_SECRET,
      signOptions: { expiresIn: '60s' },
    }),
  ],
  providers: [JwtStrategy, AuthService],
  exports: [AuthService, JwtModule],
})
export class AuthModule {}

内容的提问来源于stack exchange,提问作者Luciano Pulido

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 21:48:18