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

NestJS+GraphQL角色守卫中req.user为undefined问题求助

问题原因与解决方案

核心原因

  1. 未在非登录接口应用JWT认证守卫:登录流程用的是LocalStrategy(对应GqlAuthGuard),仅负责验证账号密码并生成JWT。后续请求需要通过JwtStrategy解析请求中的JWT,将用户信息注入req.user,但你在UserResolver的接口上没有应用JWT认证守卫,导致Passport无法处理用户身份解析。
  2. 装饰器冲突:UserResolver的getAll接口同时标记了@IsPublic()和@Roles(),如果@IsPublic()的作用是跳过认证流程,那么即使添加了角色守卫,也没有经过身份认证步骤,自然无法获取req.user。
  3. 角色守卫依赖前置认证: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 };
  }
}

验证步骤

  1. 登录获取JWT token
  2. 在请求头中添加Authorization: Bearer <你的token>
  3. 调用getAll接口,此时req.user应该能正确获取到用户信息,角色守卫也能正常校验权限

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 14:22:49