NestJS+GraphQL角色守卫中req.user为undefined问题求助
问题原因与解决方案
核心原因
- 未在非登录接口应用JWT认证守卫:登录流程用的是
LocalStrategy(对应GqlAuthGuard),仅负责验证账号密码并生成JWT。后续请求需要通过JwtStrategy解析请求中的JWT,将用户信息注入req.user,但你在UserResolver的接口上没有应用JWT认证守卫,导致Passport无法处理用户身份解析。 - 装饰器冲突:
UserResolver的getAll接口同时标记了@IsPublic()和@Roles(),如果@IsPublic()的作用是跳过认证流程,那么即使添加了角色守卫,也没有经过身份认证步骤,自然无法获取req.user。 - 角色守卫依赖前置认证:
RolesGuard仅做权限校验,不负责身份认证,必须依赖已完成认证的用户信息才能工作。
具体解决方案
1. 完善JWT认证守卫实现
确保JwtAuthGuard能正确处理GraphQL请求,并支持跳过公开接口:
import { ExecutionContext, Injectable } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { GqlExecutionContext } from '@nestjs/graphql'; import { AuthGuard } from '@nestjs/passport'; import { IS_PUBLIC_KEY } from './decorators/is-public.decorator'; @Injectable() export class JwtAuthGuard extends AuthGuard('jwt') { constructor(private reflector: Reflector) { super(); } canActivate(context: ExecutionContext) { // 检查是否标记为公开接口,是则跳过认证 const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [ context.getHandler(), context.getClass(), ]); if (isPublic) return true; return super.canActivate(context); } getRequest(context: ExecutionContext) { const ctx = GqlExecutionContext.create(context); return ctx.getContext().req; } }
2. 修正UserResolver的装饰器
移除@IsPublic()(该接口需要权限验证,不属于公开接口),同时添加JWT认证守卫和角色守卫:
@Query(() => [User]) @Roles(Role.ADMIN, Role.USER) @UseGuards(JwtAuthGuard, RolesGuard) async getAll(): Promise<User[]> { const result = await this.userService.findAll(); return result; }
3. 全局注册守卫(可选,简化代码)
如果大部分接口都需要认证,可以在AppModule全局注册JWT守卫和角色守卫,避免每个Resolver重复添加:
import { Module } from '@nestjs/common'; import { APP_GUARD } from '@nestjs/core'; import { JwtAuthGuard } from './auth/jwt-auth.guard'; import { RolesGuard } from './auth/role-guard'; @Module({ providers: [ { provide: APP_GUARD, useClass: JwtAuthGuard, }, { provide: APP_GUARD, useClass: RolesGuard, }, ], }) export class AppModule {}
4. 确保JWT策略配置正确
验证JwtStrategy能正确从请求头提取JWT并解析用户信息:
import { Injectable } from '@nestjs/common'; import { PassportStrategy } from '@nestjs/passport'; import { ExtractJwt, Strategy } from 'passport-jwt'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor() { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, secretOrKey: process.env.JWT_SECRET, // 确保配置了正确的JWT密钥 }); } async validate(payload: any) { // 返回的对象会被注入到req.user中 return { id: payload.sub, email: payload.email, role: payload.role }; } }
验证步骤
- 登录获取JWT token
- 在请求头中添加
Authorization: Bearer <你的token> - 调用
getAll接口,此时req.user应该能正确获取到用户信息,角色守卫也能正常校验权限
内容的提问来源于stack exchange,提问作者Kauã
相关产品推荐
相关产品推荐

