NestJS中Guards与Passport Strategies底层工作原理解析
NestJS Passport Guard 与 Strategy 协作原理解答
核心绑定规则
你自定义的RtGuard继承AuthGuard('jwt-refresh')后,会自动通过字符串标识jwt-refresh匹配到你用PassportStrategy(Strategy, 'jwt-refresh')注册的刷新令牌策略,不需要手动调用策略方法。
完整认证执行流程
整个校验过程分4个固定阶段执行,你观察到的「错误token不进入Strategy逻辑」是阶段3的内置拦截机制导致的:
- 守卫触发阶段:请求命中被
@UseGuards(RtGuard)装饰的GraphQL Mutation时,Nest会执行RtGuard从父类AuthGuard继承的canActivate核心逻辑。 - 请求适配阶段:
canActivate首先调用你重写的getRequest方法,将GraphQL专属执行上下文转换为通用的Express Request对象,这一步无论token是否合法都会执行——也就是你写的console.log('REFRESH')每次请求都会打印的原因。 - Passport内置JWT校验阶段:拿到Request对象后,AuthGuard会将请求交给Passport框架调度对应策略,首先执行
passport-jwt包内置的基础校验逻辑,这部分逻辑早于你自定义的validate方法执行:- 按照配置的
ExtractJwt.fromAuthHeaderAsBearerToken()规则从Authorization头提取Bearer格式的token,提取失败直接返回401 - 用配置的
REFRESH_TOKEN_SECRET校验JWT签名合法性,签名伪造、token结构损坏直接返回401 - 因为你配置了
ignoreExpiration: false,会同步校验token是否在有效期内,过期直接返回401
以上任意一步失败,请求都会被直接拦截,根本不会进入你写的Strategy类的validate方法,这和你测试的现象完全一致。
- 按照配置的
- 自定义业务校验阶段:只有内置JWT校验全部通过,Passport才会把解析完成的JWT payload传入你写的
validate方法,执行自定义逻辑:- 你当前的逻辑是二次提取请求头中的refreshToken字符串,拼到payload上返回
- 如果这一步抛出异常,会按异常类型返回对应状态码(比如你写的token格式错误抛403)
validate方法的返回值会被AuthGuard自动挂载到req.user属性上,后续Resolver、Service中可以直接取到登录用户信息。
代码优化提示
你在validate中提取refreshToken的逻辑存在兼容问题:
// 原逻辑只能精确匹配大写Bearer+单空格的格式,遇到多空格、小写bearer会残留多余字符 const refreshToken = req.get('authorization')?.replace('Bearer', '').trim();
建议替换为不区分大小写、匹配任意前缀空白的正则写法:
const refreshToken = req.get('authorization')?.replace(/^Bearer\s+/i, '').trim();
内容的提问来源于stack exchange,提问作者69JonDoe69
相关产品推荐
相关产品推荐

