登录接口bcrypt.compare报错:参数非法/参数缺失
登录接口bcrypt验证报错排查与解决
问题现象
开发登录接口生成Auth Token时,创建用户接口可正常运行,但发起登录认证请求时返回内部服务器错误,切换bcryptjs和bcrypt库均出现参数相关报错。
报错信息
使用bcryptjs时的报错
Illegal arguments: string, undefined [nodemon] restarting due to changes... [nodemon] starting `node server.js index.js` at _async (D:\Web Development\REACT PROJECTS\inotebook\backend\node_modules\bcryptjs\dist\bcrypt.js:286:46) at D:\Web Development\REACT PROJECTS\inotebook\backend\node_modules\bcryptjs\dist\bcrypt.js:307:17 at new Promise (<anonymous>) at Object.bcrypt.compare (D:\Web Development\REACT PROJECTS\inotebook\backend\node_modules\bcryptjs\dist\bcrypt.js:306:20) at new Promise (<anonymous>) at Object.bcrypt.compare (D:\Web Development\REACT PROJECTS\inotebook\backend\node_modules\bcryptjs\dist\bcrypt.js:306:20) at D:\Web Development\REACT PROJECTS\inotebook\backend\routes\auth.js:73:42 at processTicksAndRejections (node:internal/process/task_queues:96:5)
替换为bcrypt库后的报错
Error: data and hash arguments required at Object.compare (D:\Web Development\REACT PROJECTS\inotebook\backend\node_modules\bcrypt\bcrypt.js:208:17) at D:\Web Development\REACT PROJECTS\inotebook\backend\node_modules\bcrypt\promises.js:29:12 at new Promise (<anonymous>) at Object.module.exports.promise (D:\Web Development\REACT PROJECTS\inotebook\backend\node_modules\bcrypt\promises.js:20:12) at Object.compare (D:\Web Development\REACT PROJECTS\inotebook\backend\node_modules\bcrypt\bcrypt.js:204:25) at D:\Web Development\REACT PROJECTS\inotebook\backend\routes\auth.js:73:42 at processTicksAndRejections (node:internal/process/task_queues:96:5)
相关代码片段
报错集中在auth.js的bcrypt.compare调用处:
const {email, password} = req.body; try { let user = await User.findOne({email}); if(!user){ return res.status(400).json({error: "Please try to login with correct credentials"}); } const passwordCompare = await bcrypt.compare(password, user.password); if(!passwordCompare){ return res.status(400).json({error: "Please try to login with correct credentials"}); }
完整auth.js代码
const express = require('express'); const User = require('../models/User'); const router = express.Router(); const { body, validationResult } = require('express-validator'); const bcrypt = require('bcryptjs'); var jwt = require('jsonwebtoken'); const JWT_SECRET = 'usisagoodb$oy'; // Create a User using: POST "/api/auth/createuser". No login required router.post('/createuser', [ body('name', 'Enter a valid name').isLength({ min: 3 }), body('email', 'Enter a valid email').isEmail(), body('password', 'Password must be atleast 5 characters').isLength({ min: 5 }), ], async (req, res) => { // If there are errors, return Bad request and the errors const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); } try { // Check whether the user with this email exists already let user = await User.findOne({ email: req.body.email }); if (user) { return res.status(400).json({ error: "Sorry a user with this email already exists" }) } const salt = await bcrypt.genSalt(10); const secPass = await bcrypt.hash(req.body.password, salt); // Create a new user user = await User.create({ name: req.body.name, password: secPass, email: req.body.email, }); const data = { user:{ id: user.id } } const authtoken = jwt.sign(data, JWT_SECRET); // res.json(user) res.json({authtoken}) } catch (error) { console.error(error.message); res.status(500).send("Internal Server Error"); } }) // Authenticate a User using: POST "/api/auth/login". No login required router.post('/login', [ body('email', 'Enter a valid email').isEmail(), body('password', 'Password cannot be blank').exists(), ], async (req, res) => { // If there are errors, return Bad request and the errors const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); } const {email, password} = req.body; try { let user = await User.findOne({email}); if(!user){ return res.status(400).json({error: "Please try to login with correct credentials"}); } const passwordCompare = await bcrypt.compare(password, user.password); if(!passwordCompare){ return res.status(400).json({error: "Please try to login with correct credentials"}); } const data = { user:{ id: user.id } } const authtoken = jwt.sign(data, JWT_SECRET); res.json({authtoken}) } catch (error) { console.error(error); res.status(500).send("Internal Server Error"); } }) module.exports = router
问题分析与解决
两个库的报错核心都是bcrypt.compare的参数缺失或非法:bcrypt.compare(password, user.password)中,要么password为undefined,要么user.password为undefined。
结合代码来看,创建用户时已正确加密并存储密码,所以大概率是查询用户时未返回password字段,原因可能有两种:
- User模型Schema未定义password字段:Mongoose不会存储未在Schema中声明的字段,导致数据库中没有password数据。
- Schema中password设置了
select: false:该配置会让Mongoose默认查询时不返回password字段。
解决步骤
- 检查User模型Schema:确保包含password字段,示例如下:
const mongoose = require('mongoose'); const UserSchema = new mongoose.Schema({ name: { type: String, required: true }, email: { type: String, required: true, unique: true }, password: { type: String, required: true } // 必须声明该字段 }); module.exports = mongoose.model('User', UserSchema);
- 如果Schema中password设置了
select: false:在登录查询时显式指定返回password字段:
// 将原查询代码修改为 let user = await User.findOne({email}).select("+password");
- 临时调试验证:在
bcrypt.compare前添加打印语句,确认参数是否存在:
console.log("Request password:", password); console.log("User password from DB:", user.password);
内容的提问来源于stack exchange,提问作者Upmanyu Sharma
相关产品推荐
相关产品推荐

