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

NestJs授权场景下无法获取用户数据问题求助

问题描述

在NestJS的roles.guard.ts里执行const { user } = context.switchToHttp().getRequest();时,user是undefined;但删掉其他代码只保留这段获取逻辑并打印时,user又能正常拿到。相关代码片段如下:

roles.guard.ts

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';

@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);
    if (!requiredRoles) {
      return true;
    }
    const { user } = context.switchToHttp().getRequest();// user不存在
    return requiredRoles.some((role) => user.roles?.includes(role));
  }
}

roles.enum.ts

export enum Role {
    User = 'User',
    Admin = 'Admin'
}

app.module.ts

@Module({
    imports: [
        ConfigModule.forRoot(),
        AuthModule,
        UserModule,
        ProductModule,
        ReviewModule,
        OrderModule,
        CategoryModule
    ],
    controllers: [AppController],
    providers: [
        AppService,
        PrismaService,
        {
            provide: APP_GUARD,
            useClass: RolesGuard
        }
    ]
})
export class AppModule {}
问题根源

你把RolesGuard注册成了全局守卫,它会比负责用户认证的AuthGuard先执行。这时候AuthGuard还没完成认证流程,根本没把user挂载到request对象上,自然拿不到值。而你单独测试获取user的逻辑时,应该是在已经走了AuthGuard认证的路由上测的,这时候request上已经有user了,所以能正常拿到。

解决方法

方法1:让RolesGuard先完成认证再做权限判断

修改roles.guard.ts,让它继承AuthGuard(替换成你项目里用的认证策略,比如jwt),先执行认证逻辑确保user存在:

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class RolesGuard extends AuthGuard('jwt') implements CanActivate {
  constructor(private reflector: Reflector) {
    super();
  }

  async canActivate(context: ExecutionContext): Promise<boolean> {
    // 先执行AuthGuard的认证,确保user被挂载到request
    const isAuthenticated = await super.canActivate(context);
    if (!isAuthenticated) {
      return false;
    }

    const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);
    if (!requiredRoles) {
      return true;
    }
    const { user } = context.switchToHttp().getRequest();
    return requiredRoles.some((role) => user.roles?.includes(role));
  }
}

方法2:取消全局守卫,局部配合AuthGuard使用

删掉app.module.ts里的全局RolesGuard注册,改为在需要权限验证的控制器/路由上,通过@UseGuards()把AuthGuard和RolesGuard按顺序放一起(先执行AuthGuard):

修改app.module.ts:

@Module({
    imports: [
        ConfigModule.forRoot(),
        AuthModule,
        UserModule,
        ProductModule,
        ReviewModule,
        OrderModule,
        CategoryModule
    ],
    controllers: [AppController],
    providers: [
        AppService,
        PrismaService
        // 移除全局RolesGuard的注册
    ]
})
export class AppModule {}

然后在控制器里使用:

import { Controller, Get, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { RolesGuard } from './roles.guard';
import { Roles } from './roles.decorator';
import { Role } from './roles.enum';

@Controller('admin')
@UseGuards(AuthGuard('jwt'), RolesGuard) // 顺序不能乱,先认证再校验角色
export class AdminController {
  @Get()
  @Roles(Role.Admin)
  getAdminData() {
    return { message: 'Admin data' };
  }
}

方法3:确认ROLES_KEY常量定义正确

检查你的roles.decorator.ts里是否正确定义了ROLES_KEY,避免因键不匹配导致逻辑异常:

import { SetMetadata } from '@nestjs/common';
import { Role } from './roles.enum';

export const ROLES_KEY = 'roles';
export const Roles = (...roles: Role[]) => SetMetadata(ROLES_KEY, roles);

内容的提问来源于stack exchange,提问作者Тарас Гуледза

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 00:22:24