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,提问作者Тарас Гуледза
相关产品推荐
相关产品推荐

