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

