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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 22:45:50