路由守卫 守卫住网站的安全 也守住我们的幸福

哈喽,各位掘友们!

今天咱们不聊虚的,来聊聊后端开发中那个让人"又爱又恨"的角色------路由守卫(Guard)

想象一下,你的 NestJS 服务器就是一个戒备森严的"夜店"。门口站着的那个戴着墨镜、拿着名单核对身份的保安大哥,就是我们要讲的 Guard。没有他点头,哪怕你穿得再帅(请求格式再对),也别想进去嗨皮(执行业务逻辑)。

特别是当我们要实现新增文章、点赞这些需要登录的操作时,这个保安大哥的作用就更关键了。来,搬好小板凳,咱们开始实操吧!

为什么我们需要 Guard?

在没有 Guard 之前,我们处理鉴权可能喜欢在 Controller 里写一堆 if (!token) throw ...。这就好比让调酒师一边摇酒一边还要去门口查身份证,乱套了!

NestJS 的 @UseGuards() 装饰器,就是把这个查身份证的逻辑抽离出来。它会在路由处理方法执行之前先跑一遍:

  • 鉴权失败? 直接抛出 401,把请求踹飞,Controller 里的代码压根不会执行。
  • 鉴权成功? 恭喜你,放行!而且聪明的 Guard 还会把从 JWT 里解析出来的用户信息,偷偷塞进 req.user 里,让你在业务代码里随手就能拿到。

️ 打造我们的"保安队长":JWT Guard

很多掘友在初学时会遇到一个经典的报错:Unknown authentication strategy "jwt"。这通常是因为你只引入了 AuthGuard('jwt'),却忘了告诉 Passport 咱们的"jwt 策略"到底长啥样。

咱们先来把这个策略补齐,顺便把 Access Token 的校验逻辑写好:

scala 复制代码
// src/auth/jwt.strategy.ts
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy, ExtractJwt } from 'passport-jwt';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      // 就像保安检查客人的手环,我们从请求头里提取 Bearer Token
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false, // 过期了就是过期了,绝不姑息
      secretOrKey: process.env.TOKEN_SECRET || "", // 只有拿对了对暗号(密钥),才能解开 Token
    });
  }

  // 校验通过后,payload 里的信息会被挂载到 req.user 上
  async validate(payload: any) {
    // 返回的对象会自动变成 req.user
    return { id: payload.sub, name: payload.name };
  }
}

有了策略,我们再封装一个简单的 Guard:

scala 复制代码
// src/auth/guards/jwt-auth.guard.ts
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}

实战:给新增文章接口装上"防盗门"

现在,咱们的保安就位了。假设你要发一篇关于《震惊!前端居然也能写后端》的文章,这个 /posts 的 POST 接口肯定不能谁都能调,不然论坛就炸了。

这时候,@UseGuards() 就闪亮登场了:

less 复制代码
// src/posts/posts.controller.ts
import { Controller, Post, Body, UseGuards, Req } from '@nestjs/common';
import { PostsService } from './posts.service';
import { JwtAuthGuard } from '../auth/guard/jwt-auth.guard';

@Controller('posts')
export class PostsController {
  constructor(private readonly postsService: PostsService) {}

  @Post()
  @UseGuards(JwtAuthGuard) //  只要加上这一行,没带有效 Access Token 的直接拒之门外
  createPost(
    @Body('title') title: string,
    @Body('content') content: string,
    @Req() req
  ) {
    // 这里的 req.user 就是刚才 JwtStrategy 里 validate 返回的对象
    const { user } = req; 
    console.log('当前发帖用户ID:', user.id);
    
    return this.postsService.createPost({
      title,
      content,
      userId: user.id
    });
  }
}

双 Token 与无感刷新的"骚操作"

既然咱们提到了鉴权,那就不得不聊聊 Axios 拦截器里的"无感刷新"。这可是提升用户体验的神器。

流程大概是这样的:

  1. Axios 请求拦截器 :每次发请求前,自动把 access_token 塞进 Header 的 Authorization 字段里。
  2. Access Token 过期 :当你正在激情输出评论时,突然 Access Token 挂了,后端返回 401
  3. Axios 响应拦截器 :捕捉到这个 401 错误,暂停 原本的请求,默默拿出藏得很深的 refresh_token 去找后端换个新的 Access Token。
  4. 重试 :拿到新 Token 后,更新本地存储,然后把刚才失败的请求重放一遍。

对于用户来说,整个过程就像什么都没发生过一样,丝滑~

当然,这里有个坑要注意:并发问题。如果页面同时发了 5 个请求都因为 Token 过期挂了,可别傻傻地去刷新 5 次 Token!记得加个锁或者用队列机制,保证同一时间只有一个刷新请求在飞。


好啦,今天的"安保知识"就分享到这。希望各位掘友的代码都能像经过严格安检的 VIP 通道一样,既安全又流畅!如果你觉得这篇笔记对你有帮助,别忘了点个赞哦,咱们下期见!

相关推荐
ZJY1323 天前
2-1:在NestJS中使用mikro-orm
后端·nestjs
用户57573033462410 天前
拒绝“明文”裸奔!NestJS + Bcrypt 打造企业级用户注册与异常防御体系
nestjs
yuanlaile19 天前
NestJS实战商城与云原生落地指南
云原生·nestjs·nestjs学习指南
小二李24 天前
DTO,DAO是什么?MVC是什么架构?
nestjs
Ticnix1 个月前
NestJs--Prisma 7的安装与数据库配置(超完整)
前端·nestjs
小蜜蜂dry1 个月前
nestjs实战-登录、鉴权(二)
前端·后端·nestjs
全栈王校长1 个月前
Nest 文件上传 - 就是增强版的 el-upload
前端·后端·nestjs
小蜜蜂dry1 个月前
nestjs实战-登录、鉴权(一)
前端·后端·nestjs
小蜜蜂dry1 个月前
nestjs实战 - 拦截器,统一处理接口请求与响应结果
前端·后端·nestjs