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

如何在NestJS控制器中让指定路由忽略@UseGuards()守卫?

让特定路由绕过控制器级JWT守卫的解决方案

嘿,这个需求我之前也遇到过,在NestJS里要实现控制器级加了JWT守卫,但某个方法要开放成公共路由,其实有挺优雅的实现方式,我给你一步步拆解:

1. 先整个@Public装饰器标记公共路由

首先我们需要一个自定义装饰器,用来告诉守卫“这个路由不用验证”。新建一个装饰器文件:

// src/common/decorators/public.decorator.ts
import { SetMetadata } from '@nestjs/common';

export const Public = () => SetMetadata('isPublic', true);

这个装饰器的作用就是给路由打上一个isPublic的元数据标记,后面守卫会读取这个标记来判断是否跳过验证。

2. 修改你的JWT守卫逻辑

如果你之前用的是默认的AuthGuard('jwt'),现在我们需要自定义一个继承它的守卫,加上读取元数据的逻辑。新建一个守卫文件:

// src/common/guards/jwt-auth.guard.ts
import { ExecutionContext, Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { Reflector } from '@nestjs/core';

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

  canActivate(context: ExecutionContext) {
    // 先检查当前路由有没有被标记为公共路由
    const isPublic = this.reflector.getAllAndOverride<boolean>('isPublic', [
      context.getHandler(), // 先看方法上的元数据
      context.getClass(),   // 再看控制器上的元数据
    ]);
    // 如果是公共路由,直接放行
    if (isPublic) {
      return true;
    }
    // 不是的话,走原来的JWT验证逻辑
    return super.canActivate(context);
  }
}

这里用到了NestJS的Reflector来读取我们之前设置的元数据,优先级是方法上的标记大于控制器上的,刚好符合我们的需求。

3. 在控制器里给目标方法加装饰器

现在回到你的BooksController,把原来的@UseGuards(AuthGuard('jwt'))换成我们自定义的JwtAuthGuard,然后给all()方法加上@Public()装饰器:

import { Public } from './common/decorators/public.decorator';
import { JwtAuthGuard } from './common/guards/jwt-auth.guard';
// 其他必要的导入...

@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@ApiTags('books')
@Controller('books')
export class BooksController {
  @Post()
  async create(@Body() createBookVm: CreateBookVm) {
    //........
  }

  @Public() // 给这个方法打上公共路由标记
  @Get()
  async all() {
    //........
  }
}

偷懒的替代方案(不自定义装饰器)

如果你不想单独写装饰器文件,也可以直接在方法上用SetMetadata来标记:

import { SetMetadata } from '@nestjs/common';

// ...

@SetMetadata('isPublic', true)
@Get()
async all() {
  //........
}

这种方式和用@Public装饰器效果完全一样,只是少了个封装的步骤,看你个人习惯选哪种就行。

这样改完之后,GET /books就会变成无需授权的公共路由,不携带accessToken访问也不会返回401,而POST /books依然会走JWT验证逻辑,完美符合你的需求~

内容的提问来源于stack exchange,提问作者Ramin Bateni Parvar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 14:12:27