登录端点存储哈希密码与用户输入密码比对失败求助
登录端点哈希密码比对失败问题排查与修复
问题概述
开发登录端点时,出现存储的哈希密码与用户输入密码比对失败的情况,无法正常授权用户。通过日志定位到代码在if (!passwordMatch)分支返回401错误,尝试直接比对或哈希输入密码均未解决问题。
问题根源
- signup端点中bcrypt回调与async/await混用:使用bcrypt的回调式API(
genSalt、hash)嵌套在async函数中,可能导致哈希生成过程中的异常未被外层try/catch捕获,或执行流程出现意外,最终存储到数据库的密码哈希值不正确。 - login端点存在未声明变量与回调隐患:
hashedPasswordFromDb未使用const/let声明,可能造成全局变量污染;同时回调式的bcrypt.compare也存在潜在的异步流程问题。
修复方案
1. 重构signup端点的密码哈希逻辑(改用async/await版本的bcrypt API)
将回调式的盐生成和密码哈希替换为Promise风格的async/await调用,确保错误能被正确捕获,代码逻辑更清晰:
// Signup endpoint app.post('/signup', async (req, res) => { try { const { firstName, lastName, email, role, password } = req.body; const existingUser = await User.findOne({ email }); if (existingUser) { return res.status(400).json({ message: 'Email already exists' }); } let plainTextPassword = password; if (!plainTextPassword) { plainTextPassword = 'defaultPassword123'; } // 改用async/await生成盐和哈希密码 const salt = await bcrypt.genSalt(10); const hashedPassword = await bcrypt.hash(plainTextPassword, salt); const newUser = new User({ firstName, lastName, email, role, password: hashedPassword, }); await newUser.save(); const token = jwt.sign({ email: newUser.email }, secretKey); const expirationDate = new Date().getTime() + 3600000; const user = { firstName: newUser.firstName, lastName: newUser.lastName, email: newUser.email, role: newUser.role, id: newUser._id, _token: token, _tokenExpirationDate: expirationDate, }; const authResponse = new AuthResponseData(user); res.status(201).json(authResponse); } catch (error) { console.error(error); res.status(500).json({ message: 'Internal server error' }); } console.log(req.body) });
2. 重构login端点的密码比对逻辑(改用async/await版本的bcrypt API)
替换回调式的bcrypt.compare为async/await调用,同时修复未声明的变量问题:
// Login endpoint app.post('/login', async (req, res) => { try { const { email, password } = req.body; const userEmail = email; const userPassword = password; console.log(userEmail); console.log(userPassword); const user = await User.findOne({ email }); if (!user) { return res.status(401).json({ message: 'Invalid email or password' }); }; console.log('user verified'); console.log(user.password); console.log(userPassword); // 改用async/await比对密码 const passwordMatch = await bcrypt.compare(userPassword, user.password); console.log(passwordMatch); if (!passwordMatch) { return res.status(401).json({ message: 'Invalid email or password' }); } const token = jwt.sign({ email: user.email }, secretKey); const expirationDate = new Date().getTime() + 3600000; const loggedInUser = { firstName: user.firstName, lastName: user.lastName, email: user.email, role: user.role, id: user._id, _token: token, _tokenExpirationDate: expirationDate, }; const authResponse = new AuthResponseData(loggedInUser); res.status(200).json(authResponse); } catch (error) { console.error('Error:', error); console.error('Stack trace:', error.stack); res.status(500).json({ message: 'Internal server error' }); } });
3. 验证数据库中的密码哈希值
检查MongoDBusers集合中用户的password字段,确保是符合bcrypt格式的哈希值(通常以$2b$开头,长度约60字符)。如果之前存储了错误的哈希值,需要重新注册用户,或手动更新密码为正确的哈希值。
验证修复效果
- 重启服务,重新注册测试用户。
- 使用该用户的邮箱和密码登录,确认能成功获取授权token。
内容的提问来源于stack exchange,提问作者wenceslaus
相关产品推荐
相关产品推荐

