使用passport-local和bcryptjs的Node.js应用登录密码验证失效问题
问题分析与解决
你的问题根源在于**bcrypt.compare是异步函数**,直接用同步的if判断会把返回的Promise对象当作真值,导致无论密码对错都会进入登录成功的分支。
错误代码核心问题
看这段验证逻辑:
try { if (bcrypt.compare(password, user.password)) { return done(null, user); } else { return done(null, false, { message: "Incorrect password" }); } } catch (err) { return done(err); }
bcrypt.compare()返回的是Promise对象而非布尔值,所以if(bcrypt.compare(...))永远为true,直接执行登录成功逻辑,完全跳过了密码校验。
修复方案
有两种可行的修复方式:
方式1:使用async/await(推荐)
将verifyUser改为异步函数,用await获取密码比对的真实结果:
const verifyUser = async (username, password, done) => { try { const user = await User.findOne({ username: username }); if (user == null) { return done(null, false, { message: "No user with this username" }); } const isMatch = await bcrypt.compare(password, user.password); if (isMatch) { return done(null, user); } else { return done(null, false, { message: "Incorrect password" }); } } catch (err) { return done(err); } };
方式2:使用Promise链式调用
如果不想用async/await,也可以通过.then()处理比对结果:
const verifyUser = (username, password, done) => { User.findOne({ username: username }).then((user) => { if (user == null) { return done(null, false, { message: "No user with this username" }); } bcrypt.compare(password, user.password) .then(isMatch => { isMatch ? done(null, user) : done(null, false, { message: "Incorrect password" }); }) .catch(err => done(err)); }).catch(err => done(err)); };
额外优化建议
- 注册逻辑中的
user.save()建议改为await调用并添加错误捕获,避免未处理的Promise异常:
try { // ... 其他注册代码 await user.save(); console.log(user); res.redirect("./login"); } catch (err) { console.error(err); res.redirect("./register"); }
- 再次确认数据库中存储的密码是bcrypt哈希后的结果,确保注册流程没有直接存储明文密码(你的注册代码逻辑是正确的,但可以做个二次校验)。
内容的提问来源于stack exchange,提问作者Ollie
相关产品推荐
相关产品推荐

