Nest.js:全局注册AuthGuard并设置路由例外方案
在Nest.js中全局AuthGuard下添加匿名路由的最佳实践
嘿,这问题问得太实用了——全局注册AuthGuard确实能帮我们避免在每个路由上重复加守卫,但总有登录、注册或者公开API这类需要匿名访问的路由。下面是Nest.js官方推崇的几种最佳实践方案,你可以根据自己的场景来选:
方法一:自定义@Public()装饰器(推荐)
这是Nest官方最推荐的方式,利用元数据+Reflector来标记无需认证的路由,灵活且低耦合。
步骤1:创建@Public()装饰器
先在项目里新建一个公共装饰器文件,用来标记公开路由:
// src/common/decorators/public.decorator.ts import { SetMetadata } from '@nestjs/common'; // 定义元数据的key,用来后续识别公开路由 export const IS_PUBLIC_KEY = 'isPublic'; // 导出装饰器,给路由/控制器打上公开标记 export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
步骤2:修改你的AuthGuard,添加跳过逻辑
在全局使用的AuthGuard里,注入Reflector来读取路由上的元数据,如果是公开路由就跳过认证:
// src/auth/guards/auth.guard.ts import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { IS_PUBLIC_KEY } from '../../common/decorators/public.decorator'; @Injectable() export class AuthGuard implements CanActivate { // 注入Reflector,用来读取路由元数据 constructor(private readonly reflector: Reflector) {} async canActivate(context: ExecutionContext): Promise<boolean> { // 检查当前路由/控制器是否标记为公开 const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [ context.getHandler(), // 优先读取路由方法上的元数据 context.getClass(), // 其次读取控制器类上的元数据 ]); // 如果是公开路由,直接返回true跳过认证 if (isPublic) { return true; } // 这里写你原本的认证逻辑(比如验证JWT、检查用户会话等) const request = context.switchToHttp().getRequest(); const user = request.user; // 假设你的认证逻辑会把用户信息挂载到request上 return !!user; // 根据实际情况调整返回值 } }
步骤3:在匿名路由上使用@Public()装饰器
现在只需要在需要匿名访问的路由或者控制器上加上@Public()即可:
// src/auth/auth.controller.ts import { Controller, Get, Post } from '@nestjs/common'; import { Public } from '../common/decorators/public.decorator'; @Controller('auth') export class AuthController { // 单个路由公开:登录接口无需认证 @Public() @Post('login') login() { return { message: '登录接口,允许匿名访问' }; } // 整个控制器公开:所有路由都无需认证 @Public() @Controller('public/articles') export class PublicArticleController { @Get() getPublicArticles() { return { data: ['公开文章1', '公开文章2'] }; } } // 这个路由会触发全局AuthGuard的认证 @Get('profile') getProfile() { return { message: '用户个人信息,需要认证' }; } }
方法二:基于路由路径的全局判断(不推荐,仅作补充)
如果你不想用装饰器,也可以在AuthGuard里直接判断请求路径,但这种方法硬编码路径,不够灵活,路径变更时容易出错,只适合简单场景:
async canActivate(context: ExecutionContext): Promise<boolean> { const request = context.switchToHttp().getRequest(); // 检查请求路径是否在公开列表里 const publicPaths = ['/auth/login', '/public/articles']; if (publicPaths.includes(request.path)) { return true; } // 你的正常认证逻辑 const user = request.user; return !!user; }
注意事项
- 确保你的AuthGuard能正确注入
Reflector:如果是自定义守卫,要在构造函数里声明注入,Nest会自动处理依赖。 - 元数据优先级:
getAllAndOverride会优先读取路由方法上的元数据,再读取控制器类上的,所以可以灵活控制单个路由或整个控制器的权限。 - 如果你使用的是Nest自带的
JwtAuthGuard(比如@nestjs/jwt提供的),同样可以用这个方法,只需要在自定义的JwtAuthGuard里注入Reflector并添加跳过逻辑即可。
总的来说,自定义@Public()装饰器的方法是最符合Nest设计思想的最佳实践,它灵活、可扩展,而且能清晰地标记出公开路由,维护起来也更方便。
内容的提问来源于stack exchange,提问作者AyKarsi
相关产品推荐
相关产品推荐

