NestJS中如何在JWT passport策略validate方法内读取access token
解决方案
你只需要在JWT策略的配置项中开启passReqToCallback参数,即可在validate方法中拿到当前请求对象,既可以提取原始待校验的access token,也能直接获取当前请求的User-Agent等信息完成设备校验,这是passport-jwt官方支持的标准用法。
修改后的可直接运行代码如下:
import { ExtractJwt, Strategy } from 'passport-jwt'; import { PassportStrategy } from '@nestjs/passport'; import { Injectable, UnauthorizedException } from '@nestjs/common'; import { Request } from 'express'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor() { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, secretOrKey: process.env.JWTSecret, // 开启配置:将请求对象透传到validate回调函数 passReqToCallback: true, }); } async validate(req: Request, payload: any) { // 提取原始access token,两种写法效果一致 const rawAccessToken = ExtractJwt.fromAuthHeaderAsBearerToken()(req); // const rawAccessToken = req.headers.authorization?.replace('Bearer ', ''); // 设备一致性校验:比对当前请求UA和token签发时存入的UA const currentUserAgent = req.headers['user-agent']; if (currentUserAgent !== payload.useragent) { throw new UnauthorizedException('请求设备与token签发设备不匹配'); } return { userId: payload.sub, username: payload.username, useragent: payload.useragent }; } }
额外实现优化建议
- 存储设备特征时不建议明文把User-Agent写入JWT payload,可以将User-Agent加盐哈希后再存入,避免payload被base64解码后直接泄露客户端特征,同时也能减少字符串比对的性能开销。
- 如果要降低校验误杀率(比如浏览器小版本自动更新会导致UA字段变动),可以结合客户端主动上报的固定设备ID、常用IP段等特征组合校验,不要完全依赖容易变动的UA字段。
- 生产环境建议通过NestJS内置的ConfigService读取
JWTSecret等环境变量,不要直接在策略类中读取process.env,避免环境变量未完成加载时出现取值为空的异常。
内容的提问来源于stack exchange,提问作者Mohammed Tellesy
相关产品推荐
相关产品推荐

