nestjs学习 - 守卫

NestJS 守卫是一个实现了 CanActivate 接口的类。

一、它是什么?

在 NestJS 里,「守卫(Guard)」是一种用来控制请求是否能进入路由处理器(Controller 方法) 的机制。

通俗点说:

守卫就是"门卫"------每次请求进来之前,它会先检查一下你有没有资格进去。

  • 通过进入下一步
  • 未通过❌,请求拒绝(比如返回 403 Forbidden)

核心职责 :主要关注 授权(Authorization) 。虽然也可以做认证(Authentication),但通常认证由中间件或 Passport 策略处理,而守卫用于更细粒度的权限控制(如:只有管理员才能删除文章)。

在框架生命周期中,守卫的执行时机是:

复制代码
请求进入 → 中间件 → 守卫 → 拦截器 → 管道 → 控制器 → 服务

二、怎么用?

创建守卫

kotlin 复制代码
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
​
@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();
​
    // 简单示例:如果请求头中有 token,就放行
    const token = request.headers['authorization'];
    if (token) {
      return true; // 放行
    }
​
    // 否则拒绝
    return false;
  }
}

canActivate() 方法返回:

  • true → 允许进入控制器;
  • false → 阻止访问(会返回 403 Forbidden);
  • 也可以返回一个 Promise<boolean>Observable<boolean>(支持异步)。

应用守卫

你可以在三个层级使用守卫:

1. 方法级

kotlin 复制代码
import { UseGuards, Controller, Get } from '@nestjs/common';
import { AuthGuard } from './auth.guard';
​
@Controller('user')
export class UserController {
  @Get('profile')
  @UseGuards(AuthGuard)
  getProfile() {
    return { msg: '用户资料' };
  }
}

2. 控制器级

less 复制代码
@UseGuards(AuthGuard)
@Controller('admin')
export class AdminController {
  @Get()
  getAdminData() {
    return '后台数据';
  }
}

3. 全局守卫

javascript 复制代码
// main.ts
import { AppModule } from './app.module';
import { AuthGuard } from './auth.guard';
import { NestFactory } from '@nestjs/core';
​
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalGuards(new AuthGuard());
  await app.listen(3000);
}
bootstrap();

三、使用场景

守卫最常见的用途是:权限控制 / 身份验证

  1. 身份验证(Authentication) :检查用户是否已登录(例如验证 JWT Token 是否存在且有效)。
  2. 角色授权(Role-based Authorization) :检查当前用户是否拥有特定角色(如 admin, editor)。
  3. 权限控制(Permission-based Authorization) :检查用户是否有执行特定操作的权限(如:user:delete)。
  4. IP 地址过滤:只允许特定 IP 段的请求访问。
  5. 功能开关:根据配置动态开启或关闭某些接口。
  6. 请求时间限制(比如只允许工作时间访问)

你可以把它理解为:

在"进入接口之前"的最后一道防线。

四、中间件 vs 守卫

1. 中间件

中间件 是通用的"流水线工人",负责处理请求的通用逻辑(如日志、解析数据),它不知道具体的业务逻辑是什么。

中间件的盲区 : 当中间件运行时,NestJS 还没有确定最终由哪个 Controller 的哪个方法来处理请求。因此,中间件无法知道当前请求是否需要"管理员权限"。你无法在中间件里写:"如果这个路由用了 @Roles('admin') 装饰器,则检查角色"。

2. 守卫:

守卫 是专业的"安检员",专门负责授权决策 (能不能进),它完全知道即将执行哪个具体的控制器方法,并能根据元数据做判断。

守卫的全知视角

守卫接收 ExecutionContext 对象。通过这个对象,你可以拿到:

  • context.getClass(): 当前的 Controller 类。
  • context.getHandler(): 当前正在执行的方法。
  • 结合 Reflector,你可以读取该方法上所有的装饰器元数据(例如 @Roles('admin'))。
  • 结论 :凡是需要根据路由元数据 (装饰器)来做判断的逻辑,必须用守卫。

3. 核心区别对比表

特性 中间件 (Middleware) 守卫 (Guard)
主要职责 通用逻辑:日志、压缩、Cookie 解析、原始请求预处理。 授权 (Authorization) :决定请求是否允许执行特定的 Handler。
执行时机 最早。在守卫、拦截器、管道之前执行。 中间。在中间件之后,拦截器和管道之前执行。
上下文感知 。只知道 reqres不知道具体要调用哪个 Controller 或哪个方法。 。拥有 ExecutionContext,知道具体的 Class、Handler 方法、参数类型等。
访问元数据 无法直接访问 路由装饰器(如 @Roles, @Get)定义的元数据。 可以访问 。配合 Reflector 可以轻松读取路由上的自定义元数据。
返回值/控制流 必须调用 next() 才能继续,或者直接 res.end() 结束响应。 返回 boolean (或 Promise/Observable)。true 放行,false 拒绝(抛出异常)。
依赖注入 支持,但配置稍显繁琐(通常通过 forRoot 或模块配置)。 完美支持,像普通 Service 一样注入依赖。
适用场景 记录所有请求日志、解析 JSON/Cookie、设置 CORS、Gzip 压缩。 检查 JWT、验证用户角色、IP 白名单、基于权限的访问控制。
相关推荐
chaofan9801 小时前
2026 轻量模型三国杀:Flash-Lite vs GPT-4.1 Nano vs Haiku,技术选型到底该站谁?
前端·人工智能·microsoft
Lsx-codeShare2 小时前
前端发版后页面白屏?一套解决用户停留旧页面问题的完整方案
前端·javascript·前端框架·vue·vite
心柠2 小时前
TypeScript的知识梳理
前端·javascript·typescript
Cache技术分享2 小时前
354. Java IO API - 获取路径信息
前端·后端
北寻北爱2 小时前
面试篇-vue中第三方库的使用(echarts)
前端
luanma1509802 小时前
Spring 框架——@Retryable 注解与 @Recover 注解
java·前端·spring
llxxyy卢2 小时前
polar-web部分中等题目
android·前端·sql·web安全
非凡ghost2 小时前
Zen Browser:基于 Firefox 的极简开源浏览器,隐私与速度兼得
前端·网络·windows·学习·开源·firefox·软件需求
ivwsjc2 小时前
vue3 echarts地图点到点之间的飞线图
前端·javascript·vue·echarts