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

NestJS-Passport JWT策略未将用户对象附加到请求中

问题

我正在基于Next.js前端(使用NextAuth)和NestJS+GraphQL后端(使用Passport JWT)构建认证流程。NextAuth从第三方提供商获取JWT令牌并附加到请求头中,后端通过全局认证守卫处理该请求。

以下是守卫代码:

@Injectable()
export class GqlAuthGuard extends AuthGuard('jwt') {
  constructor(@Inject(UserRoleMetadataService) private readonly userRoleMetadataService: UserRoleMetadataService) {
    super();
  }

  canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
    if (this.userRoleMetadataService.isPublicResource(context)) {
      return true;
    }

    return super.canActivate(context);
  }

  getRequest(context: ExecutionContext) {
    const ctx = GqlExecutionContext.create(context);
    return this.userRoleMetadataService.getRequestWithAuthHeaders(ctx);
  }
}

策略中的validate方法:

async validate(req, payload: KnomeJwtPayload): Promise<UserEntity> {
    const user = await this.userService.getOrCreateUser(payload);

    await this.verifyAuthorization(req, user.roles);
    const isOwnerRequired = this.userRoleMetadataService.readIsOwnerRequiredHeader(req);
    if (isOwnerRequired) {
      this.verifyOwnership(req, user.id);
    }

    return user;
  }

以及用户装饰器:

const CurrentUser = createParamDecorator((data, ctx) => {
  const context = GqlExecutionContext.create(ctx).getContext();
  return context.req.user;
})

流程执行到策略的return语句前一切正常,我已确认返回的user对象符合预期,但该对象未附加到请求中,导致装饰器中获取的context.req.user为undefined。请问我哪里操作有误?

解决方案

检查以下几个关键点:

  • 确认getRequest返回的请求对象是否和上下文一致
    Passport会把validate返回的user挂载到getRequest返回的请求对象上。如果userRoleMetadataService.getRequestWithAuthHeaders(ctx)返回的是新创建的对象,而非GraphQL上下文中原有的req,那挂载的user自然不会出现在上下文的req里。可以改成直接操作上下文的req:

    getRequest(context: ExecutionContext) {
      const ctx = GqlExecutionContext.create(context);
      const req = ctx.getContext().req;
      // 把认证头附加到原req上,而非返回新对象
      this.userRoleMetadataService.attachAuthHeadersToReq(req, ctx);
      return req;
    }
    
  • 检查GraphQL上下文的配置
    在NestJS的GraphQL模块配置里,必须确保上下文正确传递请求对象:

    GraphQLModule.forRoot({
      // 其他配置项
      context: ({ req }) => ({ req }),
    })
    

    如果上下文里的req不是同一个引用,或者未正确传递,Passport挂载的user就无法被装饰器获取。

  • 核对validate方法的参数顺序
    Passport JWT策略的validate方法默认参数顺序是(payload, req),而非(req, payload)。如果你的策略继承自PassportStrategy(Strategy),必须修正参数顺序:

    async validate(payload: KnomeJwtPayload, req: Request): Promise<UserEntity> {
      // 原有逻辑
    }
    

    参数顺序错误会导致req指向错误,进而影响user的挂载逻辑。

  • 确认全局守卫的注册方式
    确保在AppModule里正确注册全局守卫:

    providers: [
      {
        provide: APP_GUARD,
        useClass: GqlAuthGuard,
      },
    ],
    

    错误的注册方式会导致守卫逻辑未正确执行,user也就不会被挂载。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 11:57:27