You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 16:15:10