修改密码路由校验历史密码时出现Bcrypt参数缺失错误如何解决
报错根因
你有四处核心错误共同导致了这个问题:
- 直接触发报错的原因:
user.newPassword是不存在的字段,用户提交的新密码应该从请求体req.body.newPassword获取,你传了undefined给bcrypt.hash的第一个参数,直接触发了参数缺失报错。 - 逻辑错误:bcrypt 哈希每次都会自动生成随机盐,哪怕是同一个密码,两次哈希得到的结果完全不同,你提前给新密码做哈希再和历史哈希比对的逻辑本身就不可能生效。
- 参数顺序错误:
bcrypt.compare的正确入参顺序是(明文密码, 已存储的哈希值),你把两个参数传反了,就算前面的问题解决了也会比对失败。 - 异步逻辑错误:你用
async作为forEach的回调,forEach不会等待异步操作执行完成,里面抛出的错误不会被外层try catch捕获,校验逻辑等于完全失效,后续修改密码的代码会在校验没完成的情况下提前执行。
修复方案
1. 修正修改密码路由代码
你不需要提前哈希新密码,直接用明文新密码和历史哈希比对即可,同时替换forEach为for...of处理异步逻辑:
router.patch("/api/user/change-password", auth, async (req, res) => { try { const user = req.user // 从请求体取新密码,先判空 const newPassword = req.body.newPassword if (!newPassword) { return res.status(400).send({error: "新密码不能为空"}) } // 遍历历史密码哈希做比对 for (const oldHashedPassword of user.usedPasswords) { const isUsed = await bcrypt.compare(newPassword, oldHashedPassword) if (isUsed) { return res.status(400).send({error: "该密码已被使用过,请更换新密码"}) } } // 清空旧令牌 user.tokens = [] // 赋值新密码,交由pre save中间件处理哈希和存入历史数组 user.password = newPassword await user.save() // 生成新令牌返回 const token = await user.generateAuthToken() res.send({token}) } catch (err) { res.status(500).send({error: err.message}) } })
2. 优化pre save中间件逻辑
建议增加历史密码长度限制,避免数组无限增长:
userSchema.pre(`save`, async function (next) { const user = this if (user.isModified(`password`)) { user.password = await bcrypt.hash(user.password, 10) // 可选:只保留最近5次使用的密码,可按需调整长度 if (user.usedPasswords.length >= 5) { user.usedPasswords.shift() } user.usedPasswords.push(user.password) } next() })
内容的提问来源于stack exchange,提问作者Jake Smith
相关产品推荐
相关产品推荐

