Node.js授权问题:passwordChangedAt不显示且无法访问decoded.iat
问题排查与解决方案
1. 排查passwordChangedAt字段不显示的原因
- 检查Schema的
select配置:如果你的Schema中给passwordChangedAt设置了select: false,那么查询文档时默认不会返回该字段,这会导致Postman中看不到它。
示例修正:passwordChangedAt: { type: Date, // 去掉select: false,或者在查询时手动指定返回该字段 } // 查询时手动返回字段的写法 User.findById(userId).select('+passwordChangedAt'); - 检查预保存钩子(pre('save')):如果有自动设置
passwordChangedAt的钩子,可能会覆盖你手动传入的值。比如密码修改逻辑中常见的钩子:
若要支持手动传入,需调整钩子逻辑,比如判断字段已被手动赋值时跳过自动设置。userSchema.pre('save', function(next) { // 仅当密码修改且不是新文档时自动设置 if (!this.isModified('password') || this.isNew) return next(); this.passwordChangedAt = Date.now() - 1000; next(); });
2. 解决decoded.iat无法访问的问题
- 确认JWT解码是否成功:如果JWT验证失败(比如密钥错误、token过期),
decoded会是null或undefined,自然无法访问iat。要确保解码代码包含错误处理:try { const decoded = jwt.verify(token, process.env.JWT_SECRET); // 后续逻辑 } catch (err) { // 处理验证失败的情况,比如token无效 } - 确认JWT生成逻辑:使用
jsonwebtoken库生成token时,默认会自动添加iat(签发时间,秒级时间戳)。如果是手动构建payload,必须手动加入iat字段:const token = jwt.sign( { id: user._id, iat: Math.floor(Date.now() / 1000) // 手动添加秒级时间戳 }, process.env.JWT_SECRET, { expiresIn: process.env.JWT_EXPIRES_IN } );
3. 关联功能的注意点(密码修改后token验证)
如果你的功能是验证token是否在密码修改后签发,要注意时间戳单位统一:
passwordChangedAt是Date类型(毫秒级),而decoded.iat是秒级,比较时需转换单位:const changedTimestamp = parseInt(user.passwordChangedAt.getTime() / 1000, 10); if (changedTimestamp > decoded.iat) { // 用户修改过密码,当前token失效 throw new Error('用户最近修改过密码,请重新登录'); }
内容的提问来源于stack exchange,提问作者Satoru gojo
相关产品推荐
相关产品推荐

