如何在PassportJS的JwtStrategy中识别Token过期状态
区分Passport JWT校验不同错误状态的实现方案
passport-jwt默认会将所有校验失败场景统一返回401 Unauthorized,要单独识别Token过期等专属状态,核心是通过自定义认证回调捕获JWT解析阶段的特定错误类型,按场景返回对应状态即可。
实现逻辑
JWT校验分为两个阶段,不同阶段的错误可以分别捕获:
- JWT格式/签名/有效期校验阶段:由底层
jsonwebtoken库直接抛出对应类型的错误- Token过期:抛出
TokenExpiredError,携带过期时间字段 - Token签名被篡改/无效:抛出
JsonWebTokenError
- Token过期:抛出
- 业务校验阶段:即查询用户是否存在的逻辑,这部分可以通过
done方法的第三个参数透传自定义错误信息
具体修改步骤
1. 替换默认的Passport认证中间件
不要直接使用passport.authenticate('jwt')的默认处理,改用自定义回调的方式接管错误响应:
// 自定义JWT认证中间件 const jwtAuth = (req, res, next) => { passport.authenticate('jwt', { session: false }, (err, user, info) => { // 处理JWT本身解析、校验阶段的错误 if (err) { // 识别Token过期场景 if (err.name === 'TokenExpiredError') { return res.status(401).json({ code: 40101, // 自定义Token过期专属业务码 message: '登录凭证已过期,请重新登录' }) } // 处理其他JWT无效场景,比如签名错误 return res.status(401).json({ code: 40102, message: '登录凭证无效' }) } // 处理无有效用户的场景 if (!user) { // 可以根据info里的信息细分场景:比如未传Token、用户不存在等 return res.status(401).json({ code: 40100, message: info?.message || '请先登录' }) } // 校验通过,将用户信息挂载到请求对象,继续执行后续逻辑 req.user = user next() })(req, res, next) }
后续路由中直接使用这个自定义中间件即可:
router.get('/user/info', jwtAuth, (req, res) => { res.json({ data: req.user }) })
2. 原有JwtStrategy的适配调整
现有策略代码基本不需要改动,只需要注意不要把配置项ignoreExpiration设为true(该值默认是false,即默认开启过期校验)即可。如果需要在用户不存在的场景透传自定义提示,可以调整done回调的传参:
const passport = require("passport") const JwtStrategy = require("passport-jwt").Strategy, ExtractJwt = require("passport-jwt").ExtractJwt const opts = {} opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken() opts.secretOrKey = JWT_SECRET passport.use( new JwtStrategy(opts, function (jwt_payload, done) { UserID.findOne({ id: jwt_payload._id }, function (err, id) { if (err) { return done(err, false) } if (id) { return done(null, id) } else { // 第三个参数透传自定义错误信息,会被上面中间件的info参数接收 return done(null, false, { message: '账号不存在或已被注销' }) } }) }) )
内容的提问来源于stack exchange,提问作者Veera Silamban
相关产品推荐
相关产品推荐

