NestJS如何全局配置角色校验 无需逐个控制器添加守卫装饰器
NestJS 全局角色守卫排除指定控制器实现方案
完全可以通过全局守卫+自定义跳过装饰器的方式实现,不需要给每个控制器重复加装饰器,步骤如下:
第一步:全局注册角色守卫
推荐用依赖注入的方式在根模块注册全局守卫,这样守卫本身可以正常注入其他依赖服务,比在main.ts直接实例化更灵活:import { Module } from '@nestjs/common'; import { APP_GUARD } from '@nestjs/core'; import { RoleGuard } from './guards/role.guard'; @Module({ // 其他模块、控制器、服务配置保持不变 providers: [ { provide: APP_GUARD, useClass: RoleGuard, }, ], }) export class AppModule {}注册完成后,所有接口请求默认都会经过
RoleGuard的校验逻辑,不需要再单独给控制器加@UseGuards(RoleGuard)装饰器。第二步:自定义跳过校验的装饰器
新建一个装饰器用来标记不需要走角色校验的控制器或接口方法:import { SetMetadata } from '@nestjs/common'; export const SKIP_ROLE_CHECK_KEY = 'skipRoleCheck'; // 装饰器可以加在控制器类上,也可以加在单个接口方法上 export const SkipRoleCheck = () => SetMetadata(SKIP_ROLE_CHECK_KEY, true);第三步:修改原有RoleGuard的逻辑
在执行角色校验前,先通过Reflector读取当前请求对应的控制器、方法上是否有跳过标记,如果有就直接放行:import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { SKIP_ROLE_CHECK_KEY } from '../decorators/skip-role-check.decorator'; import { UserRole } from '../enums/user-role.enum'; @Injectable() export class RoleGuard implements CanActivate { constructor(private readonly reflector: Reflector) {} canActivate(context: ExecutionContext): boolean { // 优先读取方法上的标记,其次读取控制器类上的标记 const needSkip = this.reflector.getAllAndOverride<boolean>(SKIP_ROLE_CHECK_KEY, [ context.getHandler(), context.getClass(), ]); if (needSkip) { return true; } // 下方直接放你原本的角色校验逻辑即可,所有没加跳过标记的接口都会走到这里 const req = context.switchToHttp().getRequest(); const currentUser = req.user; // 示例校验逻辑,替换成你自己的判断规则即可 return currentUser?.role === UserRole.Guest; } }第四步:给需要排除的特定控制器加装饰器
只需要在你要放开权限的那个控制器类上加上@SkipRoleCheck()装饰器,这个控制器下的所有接口就会跳过角色校验,其他所有控制器(包括后续新增的控制器)默认都会走全局角色拦截逻辑,不需要额外加任何装饰器。如果后续某个控制器里有个别接口需要放开,也可以单独给接口方法加这个装饰器,不用放开整个控制器。
如果你后续有其他特殊角色要求的接口,也可以在这套逻辑基础上扩展:比如保留原来的
@Role()装饰器,全局守卫里如果检测到接口加了@Role()装饰器,就用装饰器指定的角色做校验,没加的话默认用全局的Guest角色校验规则,灵活度很高。
内容的提问来源于stack exchange,提问作者user10874312
相关产品推荐
相关产品推荐

