Express+Mongoose+JWT登录路由bcrypt compare返回false问题排查
问题描述
在Node.js环境中使用Express、Mongoose开发时,注册路由可正常运行,但登录路由始终返回错误。逐行排查发现user.password返回空值,原因是User Schema未包含password字段;但添加该字段后,注册路由又无法正常工作。
用户Schema代码
//1. 引入mongoose const mongoose=require('mongoose') //2. 创建Schema const User=new mongoose.Schema({ firstName:{ type:String, required:true, }, lastName:{ type:String, required:false, }, email:{ type:String, required:true, unique:true }, username:{ type:String, required:true, unique:true }, likedSongs:{//后续改为数组类型 type:String, default:'', }, likedPlaylists:{ type:String, default:'' }, subscribedArtists:{ type:String, default:'', } }) //导出Schema module.exports=mongoose.model("User",User)
注册与登录Auth路由代码
const express=require('express') const router=express.Router() const User=require('../models/User') const bcrypt=require('bcrypt') const {getToken}=require('../utils/helpers') const passport=require('passport') router.post('/register', async (req,res)=>{ //调用/register时执行此代码,创建新用户 //req.body为包含firstname, lastname, email, username的JSON数据 const {firstName, lastName, email, username, password}=req.body //检查该邮箱是否已被注册,是则返回错误 const user= await User.findOne({email}) //匹配User Schema中的email与请求体中的email if (user) { //存在用户则返回错误 //默认状态码为200,需改为错误状态码 return res .status(403) .json({error: '该邮箱已被注册'}) } else{//用户不存在,创建新用户 //不存储明文密码,转换为哈希值 const hashedPw=bcrypt.hash(password,10) const newUserData={firstName, lastName, email, username, password: hashedPw} const newUser=await User.create(newUserData) //生成返回给用户的token const token= await getToken(email,newUser) //返回结果给用户 const userToReturn={...newUser.toJSON(),token} delete userToReturn.password return res.status(200).json(userToReturn) } }) router.post('/login', async (req,res)=>{ //从请求体获取用户名和密码 const {username,password}=req.body //检查该用户名是否存在,不存在则返回凭证无效 const user= await User.findOne({username}) if (!user) { res.status(401).json({error:'凭证无效'}) } try { await bcrypt.compare(password, user.password, (err, result) => { if (err) { return res.status(401).json({ success:false, message:'认证失败' }) } if(result) { const token = getToken(user) const loggedInUser={ token, username:user.username } return res.status(200).json({ success:true, message:'登录成功!正在跳转...', loggedInUser }) } return res.status(401).json({ success: false, message: "认证失败" }) }) } catch (error) { res.status(401).json({ success: false, message: "认证失败" }); } })
getToken函数代码
const jwt=require('jsonwebtoken') require('dotenv').config() exports={} exports.getToken= async user=>{ const token=jwt.sign( {identifier:user._id}, process.env.JWT_SECRET) return token } module.exports=exports
问题原因与修复方案
1. Schema缺失password字段
在User Schema中添加password字段,建议设置select: false避免查询时默认返回密码哈希值:
// 在User Schema中新增 password: { type: String, required: true, select: false }
2. 注册时哈希密码未等待异步操作完成
bcrypt.hash是异步函数,需添加await获取实际哈希值,否则存储的是Promise对象:
// 原代码 const hashedPw=bcrypt.hash(password,10) // 修改为 const hashedPw=await bcrypt.hash(password,10)
3. 登录路由未终止用户不存在的逻辑
if (!user)分支未添加return,会导致后续代码继续执行,需补充:
if (!user) { return res.status(401).json({error:'凭证无效'}) }
4. bcrypt.compare混用回调与await
改用Promise写法更符合async/await风格,同时getToken是异步函数需加await:
try { const result = await bcrypt.compare(password, user.password); if(result) { const token = await getToken(user); const loggedInUser={ token, username:user.username } return res.status(200).json({ success:true, message:'登录成功!正在跳转...', loggedInUser }) } return res.status(401).json({ success: false, message: "认证失败" }) } catch (error) { res.status(401).json({ success: false, message: "认证失败" }); }
5. getToken调用参数错误
注册路由中调用getToken(email,newUser),但函数仅接收user参数,修改为:
// 原代码 const token= await getToken(email,newUser) // 修改为 const token= await getToken(newUser)
内容的提问来源于stack exchange,提问作者user15697542
相关产品推荐
相关产品推荐

