Node.js中Bcrypt密码比对结果不一致问题求助
解决Bcrypt密码比对不一致的问题
这种情况我之前排查过好几次,明明明文和哈希值单独测试没问题,但在业务代码里就是不匹配,大概率是隐性的字符差异或者存储环节的小问题,给你几个落地的排查方向:
1. 先确认数据库里的哈希值有没有多余空格/隐形字符
虽然你复制的哈希值看起来是对的,但MySQL的VARCHAR字段有时候会不小心存入末尾空格,或者插入时被自动补全了空格。你可以直接在数据库里执行这条SQL验证:
SELECT username, password, TRIM(password) AS trimmed_password FROM users WHERE username = '你的测试用户名';
对比password和trimmed_password的长度,如果不一样,说明原字段有多余空格,这会直接导致bcrypt比对失败。
2. 验证业务代码里的明文密码是否“看起来一样但实际不同”
你虽然console.log出明文是test,但有可能存在看不见的特殊字符(比如零宽空格、全角空格),或者编码问题。可以在Passport的代码里加一行字节级的验证:
// 在bcrypt.compare之前添加 console.log('明文字节码:', Buffer.from(plainTextPassword).toString('hex')); // 同时在测试代码里也加一行 console.log('测试明文字节码:', Buffer.from('test').toString('hex'));
如果两个字节码不一样,说明明文密码在传递到Passport之前被篡改了,比如前端传值时的编码问题、中间件的处理逻辑(比如body-parser的配置)。
3. 检查两个项目的Bcrypt版本是否一致
不同版本的bcrypt偶尔会有兼容性问题,虽然你的哈希是$2b$前缀(大部分版本都支持),但还是确认一下:
在两个项目的终端分别执行:
npm list bcrypt
如果版本差异较大,尝试把业务代码里的bcrypt版本升级到和测试代码一致,再测试。
4. 确认数据库字段的字符集和长度
你的字段是VARCHAR(150),长度是够的(bcrypt哈希一般是60位左右),但要确认字段的字符集是utf8mb4或者utf8,避免字符集转码导致哈希值被隐性修改。可以查看表结构:
SHOW CREATE TABLE users;
看password字段的字符集配置。
附上你提供的代码格式化版本,方便参考:
问题代码(Passport LocalStrategy)
passport.use(new LocalStrategy(function(username, plainTextPassword, done) { process.nextTick(() => { db.query('SELECT * FROM users WHERE username = ?', [username], (err, rows) => { if (err) return done(err); if (!rows[0]) return done(null, false); let hash = rows[0].password; let user = rows[0]; bcrypt.compare(plainTextPassword, hash, (err, res) => { console.log(plainTextPassword); // test console.log(hash); // $2b$10$EefqCwYTMHDDtIGH.SIHIu.BPCOiT7Bp4Zzej5iUoxlKtMZ67oHtC console.log(res); // false if (!res) return done(null, false); return done(null, rows[0]); }); }); }); }));
测试代码
const bcrypt = require('bcrypt'); const saltRounds = 10; bcrypt.compare('test', '$2b$10$EefqCwYTMHDDtIGH.SIHIu.BPCOiT7Bp4Zzej5iUoxlKtMZ67oHtC', (err, same) => { console.log(same); // true });
内容的提问来源于stack exchange,提问作者Colin Harrison
相关产品推荐
相关产品推荐

