NestJS中如何全局校验用户角色 实现除指定控制器外的权限拦截
NestJS 全局配置角色拦截、排除指定控制器的实现方案
直接用全局守卫 + 自定义豁免装饰器的方案即可实现需求,不需要给每个控制器重复加装饰器,后续新增控制器也会自动生效,具体步骤如下:
- 第一步:全局注册
RoleGuard,无需在单个控制器上单独写@UseGuards(RoleGuard)
推荐在AppModule中通过APP_GUARD令牌注册,这种方式注册的守卫支持正常依赖注入(比如注入Reflector、业务服务等),代码示例:
不推荐在// app.module.ts import { APP_GUARD } from '@nestjs/core'; import { RoleGuard } from './role.guard'; @Module({ // 其余模块、控制器配置省略 providers: [ { provide: APP_GUARD, useClass: RoleGuard, }, ], }) export class AppModule {}main.ts中通过app.useGlobalGuards()注册,这种方式注册的守卫无法自动注入依赖,手动传参维护成本更高。 - 第二步:定义豁免装饰器,用来标记不需要走角色拦截的控制器/方法
基于Nest内置的SetMetadata实现自定义装饰器,支持标记整个控制器或者单个路由方法:// skip-role-check.decorator.ts import { SetMetadata } from '@nestjs/common'; export const SKIP_ROLE_CHECK_KEY = 'skipRoleCheck'; export const SkipRoleCheck = () => SetMetadata(SKIP_ROLE_CHECK_KEY, true); - 第三步:改造
RoleGuard逻辑,默认执行全局拦截规则,碰到豁免标记直接放行
守卫中先通过Reflector读取当前路由/控制器上的豁免标记,存在标记直接放行,否则执行你需要的特定角色拦截逻辑,代码示例:// role.guard.ts import { CanActivate, ExecutionContext, ForbiddenException, Injectable } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { SKIP_ROLE_CHECK_KEY } from './skip-role-check.decorator'; import { UserRole } from './user-role.enum'; // 项目内自定义的角色枚举 @Injectable() export class RoleGuard implements CanActivate { constructor(private reflector: Reflector) {} canActivate(context: ExecutionContext): boolean { // 优先读取方法上的标记,没有再读取控制器类上的标记 const skipCheck = this.reflector.getAllAndOverride<boolean>(SKIP_ROLE_CHECK_KEY, [ context.getHandler(), context.getClass(), ]); if (skipCheck) return true; // 全局默认拦截逻辑:拦截指定角色(比如Guest)访问 const request = context.switchToHttp().getRequest(); const user = request.user; // 前置鉴权守卫解析后挂载到请求上的用户信息 if (user.role === UserRole.Guest) { throw new ForbiddenException('当前角色无访问权限'); } return true; } } - 第四步:给需要排除的控制器加上豁免装饰器
只需要在你要放开权限的那个控制器类上加上@SkipRoleCheck(),该控制器下所有接口都会跳过角色校验:// 需要排除拦截的控制器 import { SkipRoleCheck } from './skip-role-check.decorator'; @SkipRoleCheck() @Controller('public') export class PublicController { // 控制器下所有接口都不会被角色守卫拦截 }
说明:不推荐用中间件实现这类需求,中间件层无法获取当前匹配的路由控制器、方法元数据,做精确豁免的逻辑会非常繁琐。上述方案是NestJS生态通用的全局权限控制实现,后续新增的所有控制器只要不加
@SkipRoleCheck装饰器,都会自动走全局角色拦截规则。如果需要保留部分接口自定义角色权限的能力,只需要在守卫中补充原有@Role装饰器的判断逻辑即可:如果路由上通过@Role指定了允许的角色列表,就走自定义角色校验,没有指定就走默认拦截规则,灵活度很高。
内容的提问来源于stack exchange,提问作者user10874312
相关产品推荐
相关产品推荐

