NestJS无保护路由下如何获取有效JWT中的用户信息?
解决方案
要实现「路由无保护但支持可选JWT解析」的需求,你不需要完全移除守卫,而是要修改守卫的验证逻辑,让它不强制要求JWT有效——仅当存在有效JWT时解析用户信息,无JWT或JWT无效时仍允许请求通行。
步骤1:修改/创建可选JWT守卫
重写原AccessTokenGuard的handleRequest方法,让它在JWT验证失败时不抛出异常,而是允许请求继续:
import { Injectable } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; @Injectable() export class OptionalAccessTokenGuard extends AuthGuard('jwt') { // 重写Passport AuthGuard的核心处理逻辑 handleRequest(err: any, user: any) { // 核心逻辑:无论验证成功与否,都允许请求通过 // 验证成功时user会被赋值,失败时user为null/undefined return user || true; } }
步骤2:在控制器中使用新守卫
将原@UseGuards(AccessTokenGuard)替换为新的可选守卫,并修改userId的取值逻辑(处理req.user可能不存在的情况):
@UseGuards(OptionalAccessTokenGuard) // 换成可选守卫 @Post() create( @Req() req: Request, @Body() createOrderDto: CreateOrderDto, ): Promise<Order> { // 使用可选链操作符处理user不存在的情况 const userId = req.user?.['sub']; return this.ordersService.create(userId, createOrderDto); }
关键说明
- 原
AuthGuard('jwt')在JWT无效/缺失时会自动抛出401 Unauthorized异常,重写handleRequest后,我们跳过了异常抛出逻辑,直接返回true允许请求继续。 - 当请求携带有效JWT时,
req.user会被正常赋值;无JWT或JWT无效时,req.user为undefined,此时userId也会是undefined,你需要在ordersService.create中处理这种匿名场景(比如生成匿名订单标记)。
备选方案(全局守卫+装饰器)
如果你的项目中有多个类似的可选验证路由,可以考虑全局守卫结合自定义装饰器:
- 创建
@Public()装饰器标记无保护路由 - 全局守卫中判断路由是否为
@Public(),如果是则执行可选JWT解析,否则强制验证
但对于单个路由来说,直接使用上述的OptionalAccessTokenGuard是最简洁的方案。
内容的提问来源于stack exchange,提问作者Dave
相关产品推荐
相关产品推荐

