NestJS 入门(3):Guard 如何挡住未登录请求?
上一篇NestJS 入门2依赖注入到底解决了什么问题 讲完了「对象怎么接到一起」。接下来更贴近业务的问题是有些接口谁都能调有些接口必须先登录。Nest 把这道门放在哪里答案是Guard守卫。实战里最常见的门是JWT Passport这一套。本文会先讲清 Guard 在链路中的位置再介绍相关插件各自干什么最后用一个最小可跑例子把「登录发 token → 带 token 访问受保护接口」串起来。1. Guard 在请求链路里的位置一个请求进 Nest 后大致顺序是请求进来 → 中间件Middleware → Guard能不能进 → 管道Pipe参数校验/转换 → Controller 方法 → Service 业务逻辑Guard 回答的是一个很单纯的问题这个请求允不允许继续往下走允许 → 进入 Controller不允许 → 直接返回 401 / 403业务代码根本不会执行这和 Service 里的业务判断不一样位置典型问题Guard你是谁有没有登录有没有权限Service密码对不对这个项目属不属于你数据怎么改鉴权门槛尽量放在 Guard业务规则放在 Service。2. JWT 相关插件各自干什么Nest 官方没有「只装一个包就搞定登录」。常见组合是下面几个职责要分清npmi nestjs/jwt nestjs/passport passport passport-jwtnpmi-Dtypes/passport-jwt包角色你平时会碰到它的地方nestjs/jwtNest 封装的 JWT 工具JwtModule.register(...)、注入JwtService去sign/verifynestjs/passport把 Passport 接到 NestPassportModule、AuthGuard(jwt)、PassportStrategypassportNode 生态里的认证框架一般不直接写很多代码但是底层依赖passport-jwtPassport 的 JWT 策略实现Strategy、ExtractJwt.fromAuthHeaderAsBearerToken()types/passport-jwtTypeScript 类型开发期类型提示可以记成一句话nestjs/jwt负责签发/校验 tokenpassportpassport-jwt负责「从请求里取出 token 并按策略认证」nestjs/passport把这套策略接到 Nest 的 Guard 上。和登录常一起出现、但不属于 JWT 本体的包作用bcrypt密码哈希与比对存库用哈希登录时compare它们在 Module 里通常这样装配import{Module}fromnestjs/common;import{JwtModule}fromnestjs/jwt;import{PassportModule}fromnestjs/passport;Module({imports:[PassportModule,JwtModule.register({secret:process.env.JWT_SECRET||your-secret-key,signOptions:{expiresIn:30m},}),],// controllers / providers ...})exportclassAuthModule{}PassportModule启用 Passport 集成JwtModule.register({ secret, signOptions })配置签名密钥和默认过期时间并提供可注入的JwtService3. 最直观的用法UseGuards登录接口本身不需要登录「我是谁」接口必须登录Controller(api/auth)exportclassAuthController{constructor(privatereadonlyauthService:AuthService){}Post(login)login(Body()body:{email:string;password:string}){returnthis.authService.login(body.email,body.password);}UseGuards(JwtAuthGuard)Get(me)me(Headers(authorization)auth:string){consttokenauth?.replace(Bearer ,);returnthis.authService.validateToken(token);}}对比一下POST /api/auth/login没有 Guard任何人都能尝试登录GET /api/auth/me挂了JwtAuthGuard没带有效 token 进不来项目列表这类业务接口也一样UseGuards(JwtAuthGuard)Get()findAll(Request()req:AuthenticatedRequest){constuserIdreq.user?.userId;returnthis.projectsService.findAll(userId);}先过 Guard再拿当前用户去查「属于我的项目」。4. 方法级 vs 控制器级Guard 可以挂在单个方法上也可以挂在整个 Controller上。方法级上面那些例子只保护某一个接口。控制器级这个 Controller 里所有接口默认都要登录Controller()UseGuards(JwtAuthGuard)exportclassTaskPromptsController{constructor(privatereadonlyservice:TaskPromptsService){}Get(api/projects/:projectId/task-prompts)list(Param(projectId)projectId:string){returnthis.service.listByProject(projectId);}Put(api/projects/:projectId/task-prompts/:templateKey)saveDraft(/* ... */){// ...}}怎么选只有少数接口要登录 → 方法级更清晰整个模块几乎都要登录 → 控制器级少写很多重复装饰器5.JwtAuthGuard为什么看起来这么短真实代码里Guard 本身可能只有一行import{Injectable}fromnestjs/common;import{AuthGuard}fromnestjs/passport;Injectable()exportclassJwtAuthGuardextendsAuthGuard(jwt){}这里用的是nestjs/passport提供的AuthGuard。jwt这个名字对应的是passport-jwt策略。真正的校验逻辑在Strategy里import{Injectable}fromnestjs/common;import{PassportStrategy}fromnestjs/passport;import{ExtractJwt,Strategy}frompassport-jwt;Injectable()exportclassJwtStrategyextendsPassportStrategy(Strategy){constructor(){super({jwtFromRequest:ExtractJwt.fromAuthHeaderAsBearerToken(),ignoreExpiration:false,secretOrKey:process.env.JWT_SECRET||your-secret-key,});}asyncvalidate(payload:any){return{userId:payload.sub,email:payload.email,name:payload.name};}}对照插件代码来自哪个包AuthGuard(jwt)nestjs/passportPassportStrategy(...)nestjs/passportStrategy/ExtractJwtpassport-jwt职责拆开角色干什么JwtAuthGuard声明这里用名为jwt的认证策略守门JwtStrategy从 Header 取 Bearer token、验签、解析 payloadvalidate()验签通过后把用户信息整理出来挂到请求上AuthGuard(jwt)里的jwt必须和策略名对得上。Nest passport-jwt的默认约定里策略名就是jwt。另外secretOrKey要和JwtModule.register({ secret })、登录时JwtService.sign用的密钥一致否则「能签发、验不过」。6. 通过 Guard 之后用户信息在哪里Strategy 的validate()返回值会被放到request.user上。所以受保护接口可以这样取当前用户interfaceAuthenticatedRequestextendsExpressRequest{user?:{userId:string;email:string;name:string};}UseGuards(JwtAuthGuard)Get(generation-preferences)getGenerationPreferences(Request()req:AuthenticatedRequest){constuserIdreq.user?.userId;if(!userId){thrownewUnauthorizedException(Unauthorized);}returnthis.authService.getGenerationPreferences(userId);}链路可以记成Authorization: Bearer token → JwtStrategy 取出并校验 tokenpassport-jwt → validate(payload) 返回 { userId, email, name } → 写入 req.user → Controller 用 Request() 读取Guard 负责「放行」Controller / Service 负责「用这个身份继续办事」。7. 签发 tokenJwtService用在 Service 里Guard / Strategy 管「验票」登录成功后「出票」通常在 Service注入nestjs/jwt的JwtServiceInjectable()exportclassAuthService{constructor(privatereadonlyjwtService:JwtService){}privateasyncgenerateTokens(user:{id:string;email:string;name:string}){constpayload{sub:user.id,email:user.email,name:user.name};constaccessTokenthis.jwtService.sign(payload,{expiresIn:30m,});constrefreshTokenthis.jwtService.sign(payload,{expiresIn:7d,});return{accessToken,refreshToken};}}常见分工动作常用 API出现位置登录成功发 tokenjwtService.sign(payload)AuthService手动校验 tokenjwtService.verify(token)少数自定义逻辑请求自动验票Strategy Guard受保护接口入口生产里 access token 短、refresh token 长是很常见的组合细节可以后续再展开入门先抓住「谁签发、谁校验」。8. 还要在 Module 里注册和上一篇 DI 一样Guard、Strategy 也是 Provider要登记。Module({imports:[PassportModule,JwtModule.register({secret:process.env.JWT_SECRET||your-secret-key,signOptions:{expiresIn:30m},}),],controllers:[AuthController],providers:[AuthService,JwtStrategy,JwtAuthGuard],exports:[AuthService,JwtAuthGuard],})exportclassAuthModule{}实用提醒JwtStrategy必须进providers否则 Guard 找不到策略其他模块要用UseGuards(JwtAuthGuard)通常需要 Auth 模块exports这个 GuardJwtModule的secret与JwtStrategy的secretOrKey必须一致nestjs/jwt、nestjs/passport、passport-jwt缺一个链路就接不上9. 可选登录OptionalJwtAuthGuard有些接口「登录了更好不登录也能看」。这时可以做可选 GuardInjectable()exportclassOptionalJwtAuthGuardextendsAuthGuard(jwt){handleRequest(err:any,user:any){returnuser;}}和强制 Guard 的差别在于校验失败时不直接把请求打死而是可能让user为空继续往下走。业务代码再判断有req.user就按登录态处理没有就按游客处理。入门阶段先掌握强制登录的JwtAuthGuard即可。10. 对照一张完整链路图1) POST /api/auth/login → AuthService 校验账号密码可用 bcrypt → JwtService.sign(...) 签发 accessToken / refreshToken 2) GET /api/projects Header: Authorization: Bearer accessToken → JwtAuthGuardnestjs/passport → JwtStrategypassport-jwt验签 → validate() 写入 req.user → Controller / Service 使用 userId如果第 2 步没有 token、token 过期、或签名不对Guard / Strategy 拦下请求Controller 根本不会执行11. 实战最小可跑的 JWT 登录 受保护接口下面用最少文件搭一条能跑通的链路。目标只有两个接口POST /auth/login账号密码正确 → 返回 tokenGET /auth/profile必须带Authorization: Bearer token11.1 安装依赖npmi nestjs/jwt nestjs/passport passport passport-jwtnpmi-Dtypes/passport-jwt11.2auth.module.ts装配插件import{Module}fromnestjs/common;import{JwtModule}fromnestjs/jwt;import{PassportModule}fromnestjs/passport;import{AuthController}from./auth.controller;import{AuthService}from./auth.service;import{JwtStrategy}from./jwt.strategy;import{JwtAuthGuard}from./jwt-auth.guard;Module({imports:[PassportModule,JwtModule.register({secret:dev-secret,// 实战请改成环境变量signOptions:{expiresIn:30m},}),],controllers:[AuthController],providers:[AuthService,JwtStrategy,JwtAuthGuard],})exportclassAuthModule{}记得在AppModule里imports: [AuthModule]。11.3auth.service.ts校验账号并签发 tokenimport{Injectable,UnauthorizedException}fromnestjs/common;import{JwtService}fromnestjs/jwt;Injectable()exportclassAuthService{// 演示用内存用户真实项目换成数据库privatereadonlyusers[{id:1,email:demoexample.com,password:password123,name:Demo},];constructor(privatereadonlyjwtService:JwtService){}login(email:string,password:string){constuserthis.users.find((u)u.emailemail);if(!user||user.password!password){thrownewUnauthorizedException(Invalid credentials);}constpayload{sub:user.id,email:user.email,name:user.name};constaccessTokenthis.jwtService.sign(payload);return{accessToken,user:{id:user.id,email:user.email,name:user.name},};}}说明这里为了最短路径用了明文密码。真实项目请用bcrypt.hash/bcrypt.compare。11.4jwt.strategy.ts从 Header 取票并验票import{Injectable}fromnestjs/common;import{PassportStrategy}fromnestjs/passport;import{ExtractJwt,Strategy}frompassport-jwt;Injectable()exportclassJwtStrategyextendsPassportStrategy(Strategy){constructor(){super({jwtFromRequest:ExtractJwt.fromAuthHeaderAsBearerToken(),ignoreExpiration:false,secretOrKey:dev-secret,// 必须和 JwtModule.register 的 secret 一致});}validate(payload:{sub:string;email:string;name:string}){return{userId:payload.sub,email:payload.email,name:payload.name};}}11.5jwt-auth.guard.ts一道门import{Injectable}fromnestjs/common;import{AuthGuard}fromnestjs/passport;Injectable()exportclassJwtAuthGuardextendsAuthGuard(jwt){}11.6auth.controller.ts公开登录 受保护资料import{Body,Controller,Get,Post,Request,UseGuards}fromnestjs/common;import{AuthService}from./auth.service;import{JwtAuthGuard}from./jwt-auth.guard;Controller(auth)exportclassAuthController{constructor(privatereadonlyauthService:AuthService){}Post(login)login(Body()body:{email:string;password:string}){returnthis.authService.login(body.email,body.password);}UseGuards(JwtAuthGuard)Get(profile)profile(Request()req:{user:{userId:string;email:string;name:string}}){returnreq.user;}}11.7 用 curl 验证登录curl-XPOST http://localhost:3000/auth/login\-HContent-Type: application/json\-d{\email\:\demoexample.com\,\password\:\password123\}把返回里的accessToken拷出来再访问受保护接口curlhttp://localhost:3000/auth/profile\-HAuthorization: Bearer 粘贴你的accessToken预期带正确 token → 返回{ userId, email, name }不带 token / token 错误 → 401进不了profile方法如果这一步跑通了你就已经同时练到了nestjs/jwt签发passport-jwt Strategy 校验nestjs/passport的 Guard 守门Controller 从req.user取当前用户12. 小结Guard 决定请求能不能进入ControllerJWT 常见插件分工nestjs/jwt出票/验票工具passport-jwt策略实现nestjs/passport接到 Nest GuardUseGuards(JwtAuthGuard)可挂在方法或整个 ControllerJwtModule.secret与JwtStrategy.secretOrKey必须一致登录用JwtService.sign访问受保护接口靠 Strategy Guard 自动验票并写入req.user对照前两篇请求相关的问题可以再多一句哪个 Controller 接请求哪个 Service 做业务哪个 Module 组装它们依赖从哪里注入这个接口有没有 GuardJWT 相关插件在这条链路上各负责哪一段下一篇可以讲统一响应与异常处理——为什么业务代码抛UnauthorizedException前端却总能收到结构一致的错误包。系列导航上一篇NestJS 入门2依赖注入到底解决了什么问题第一篇NestJS 入门1先搞懂 Module、Controller、Service

相关新闻

5个技巧掌握RVC语音转换:10分钟打造专属AI音色

5个技巧掌握RVC语音转换:10分钟打造专属AI音色

5个技巧掌握RVC语音转换&#xff1a;10分钟打造专属AI音色 【免费下载链接】Retrieval-based-Voice-Conversion-WebUI Easily train a good VC model with voice data < 10 mins! 项目地址: https://gitcode.com/GitHub_Trending/re/Retrieval-based-Voice-Conversion-Web…

2026/8/10 22:27:09 阅读更多 →
gpt-bird配置文件详解:config.json中的tokenizer与游戏引擎参数解析

gpt-bird配置文件详解:config.json中的tokenizer与游戏引擎参数解析

gpt-bird配置文件详解&#xff1a;config.json中的tokenizer与游戏引擎参数解析 【免费下载链接】gpt-bird 项目地址: https://ai.gitcode.com/hf_mirrors/gmmeyer/gpt-bird gpt-bird是一款结合AI与游戏引擎的创新项目&#xff0c;其核心配置文件config.json包含了toke…

2026/8/10 22:27:09 阅读更多 →
系统级守护进程配置:systemd/launchd/NSSM实现Docuum自动运行

系统级守护进程配置:systemd/launchd/NSSM实现Docuum自动运行

系统级守护进程配置&#xff1a;systemd/launchd/NSSM实现Docuum自动运行 【免费下载链接】docuum Docuum performs least recently used (LRU) eviction of Docker images. &#x1f5d1;️ 项目地址: https://gitcode.com/gh_mirrors/do/docuum Docuum是一款轻量级Doc…

2026/8/10 22:27:09 阅读更多 →

最新新闻

解锁500+AI模型:开源AI生成平台的完全自托管方案

解锁500+AI模型:开源AI生成平台的完全自托管方案

解锁500AI模型&#xff1a;开源AI生成平台的完全自托管方案 【免费下载链接】Open-Generative-AI Unrestricted Open-source alternative to AI video platforms — Free AI image & video generation studio with 500 models (Flux, Midjourney, Kling, Sora, Veo). No co…

2026/8/10 23:06:40 阅读更多 →
PCA-GRU模型在时间序列预测中的MATLAB实现与优化

PCA-GRU模型在时间序列预测中的MATLAB实现与优化

1. 项目概述&#xff1a;PCA-GRU回归预测模型在时间序列预测领域&#xff0c;传统方法往往难以有效处理高维数据中的噪声和冗余信息。PCA-GRU组合模型通过主成分分析&#xff08;PCA&#xff09;降维和门控循环单元&#xff08;GRU&#xff09;时序建模的协同作用&#xff0c;为…

2026/8/10 23:06:40 阅读更多 →
HelloGitHub:发现有趣开源项目的终极指南

HelloGitHub:发现有趣开源项目的终极指南

HelloGitHub&#xff1a;发现有趣开源项目的终极指南 【免费下载链接】HelloGitHub :octocat: 分享 GitHub 上有趣、入门级的开源项目。Share interesting, entry-level open source projects on GitHub. 项目地址: https://gitcode.com/GitHub_Trending/he/HelloGitHub …

2026/8/10 23:06:40 阅读更多 →
海淀区科技创新生态:顶天立地与铺天盖地的双轮驱动

海淀区科技创新生态:顶天立地与铺天盖地的双轮驱动

1. 项目背景与核心概念解析 "顶天立地"与"铺天盖地"这两个看似对立的词组&#xff0c;实际上描绘了科技创新生态系统的完整图景。作为全国科技创新中心核心区&#xff0c;海淀区在新年伊始的工作部署中&#xff0c;用这组形象比喻勾勒出区域创新发展的战略…

2026/8/10 23:06:40 阅读更多 →
GTA5 FSR终极指南:如何免费提升游戏性能50%以上

GTA5 FSR终极指南:如何免费提升游戏性能50%以上

GTA5 FSR终极指南&#xff1a;如何免费提升游戏性能50%以上 【免费下载链接】gta5_fsr Mod to replace original Grand Theft Auto V upscaler with FidelityFx Super Resolution 1.0 项目地址: https://gitcode.com/gh_mirrors/gt/gta5_fsr 想要在《侠盗猎车手5》中获得…

2026/8/10 23:06:40 阅读更多 →
Nacos微服务实践:从原理到生产环境部署

Nacos微服务实践:从原理到生产环境部署

1. 为什么选择Nacos作为微服务核心组件 在微服务架构的选型过程中&#xff0c;服务发现和配置管理是两大基石功能。Nacos作为Spring Cloud Alibaba体系的核心组件&#xff0c;其设计理念源于阿里巴巴内部多年双11高并发场景的锤炼。与传统的EurekaConfig组合相比&#xff0c;Na…

2026/8/10 23:05:40 阅读更多 →

日新闻

GraphQL-CSS API全解析:useGqlCSS、GqlCSS组件与getStyles实用指南

GraphQL-CSS API全解析:useGqlCSS、GqlCSS组件与getStyles实用指南

GraphQL-CSS API全解析&#xff1a;useGqlCSS、GqlCSS组件与getStyles实用指南 【免费下载链接】graphql-css A blazing fast CSS-in-GQL™ library. 项目地址: https://gitcode.com/gh_mirrors/gr/graphql-css GraphQL-CSS是一个基于GraphQL的CSS-in-GQL™库&#xff0…

2026/8/10 0:00:02 阅读更多 →
告别语言障碍:KISS Translator 双语翻译插件终极指南

告别语言障碍:KISS Translator 双语翻译插件终极指南

告别语言障碍&#xff1a;KISS Translator 双语翻译插件终极指南 【免费下载链接】kiss-translator A simple, open source bilingual translation extension & Greasemonkey script (一个简约、开源的 双语对照翻译扩展 & 油猴脚本) 项目地址: https://gitcode.com/…

2026/8/10 0:00:02 阅读更多 →
BepInEx配置管理器:游戏插件配置的终极可视化解决方案

BepInEx配置管理器:游戏插件配置的终极可视化解决方案

BepInEx配置管理器&#xff1a;游戏插件配置的终极可视化解决方案 【免费下载链接】BepInEx.ConfigurationManager Plugin configuration manager for BepInEx 项目地址: https://gitcode.com/gh_mirrors/be/BepInEx.ConfigurationManager 你是否曾经因为游戏插件的复杂…

2026/8/10 0:00:02 阅读更多 →

周新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑&#xff1a;baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码&#xff08;维护中 rm repo&#xff09; 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/10 1:05:29 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片&#xff1a;Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/10 1:05:29 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身&#xff0c;而应重视模型外的系统搭建&#xff0c;即Harness。提出AgentModelHarness的实用公式&#xff0c;详细介绍Harness的四个层次&#xff1a;持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/10 1:05:29 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速&#xff1a;macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/10 17:07:33 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南&#xff1a;3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗&#xff1f;ncmdump解密工具帮你轻松解决这个困…

2026/8/10 1:05:29 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片&#xff1a;为英语学习 App 打造桌面级学习助手适用平台&#xff1a;HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0&#xff08;API 26 Beta&#xff09;新增了 AgentCard 智能体卡片能力&#xff0c;这是继 HMAF&#xff08;鸿蒙智能体框架&#x…

2026/8/10 17:07:33 阅读更多 →