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

ExpressJS+Passport登录successRedirect失效及bcrypt.compare始终为false问题

NodeJS登录验证失败:bcrypt.compare始终返回false导致无法跳转首页

我是NodeJS新手,使用MySQL、ExpressJS和Passport搭建了注册/登录页面,但登录成功后未按预期跳转到首页,反而回到登录页(这本是failureRedirect的预期行为)。

更新:我发现passport.js文件中的await bcrypt.compare(password, user.password)始终返回false,导致无法进入成功分支,但不清楚原因。

相关代码

passport.js配置

const LocalStrategy = require("passport-local").Strategy
const bcrypt = require("bcrypt")


function initialize(passport, getUserByEmail, getUserById) {
    // Function to authenticate users
    const authenticateUsers = async(email, password, done) => {
        // Get users by email
        const user = await getUserByEmail(email)
        console.log(user)
        if (user == null) {
            return done(null, false, { message: "User is not registered" })
        }
        try {
            if (await bcrypt.compare(password, user.password)) {
                return done(null, user)
            } else {
                return done(null, false, { message: "Wrong credential(s)" })
            }
        } catch (e) {
            console.log(e);
            return done(e)
        }
    }

    passport.use(new LocalStrategy({ usernameField: 'email' }, authenticateUsers))
    passport.serializeUser((user, done) => done(null, user.id))
    passport.deserializeUser((id, done) => {
        return done(null, getUserById(id))
    })
}

module.exports = initialize

server.js代码

if (process.env.NODE_ENV !== "production") {
    require("dotenv").config()
}

const express = require("express")
const db = require("./config/database")
const bcrypt = require("bcrypt")
const { Prisma } = require("@prisma/client")
const initializePassport = require("./config/passport")
const flash = require("express-flash")
const session = require("express-session")
const { application } = require("express")
const passport = require("passport")
const server = express()

initializePassport(
        passport,
        async email => await db.user.findFirst({ where: { email } }),
        async id => await db.user.findFirst({ where: { id } })
    )

server.use(express.urlencoded({ extended: false })) //this code is to get the form data in req.body
server.use(flash())
server.use(session({
    secret: process.env.SESSION_SECRET,
    resave: false, // we want to resave the session variable if nothing is changed
    saveUninitialized: false
}))
server.use(passport.initialize())
server.use(passport.session())


async function main() {
    const PORT = 8080

    server.listen(PORT, function() {
        console.log(`Server started on port ${PORT}...`)
    })
}

server.get('/', async(req, res) => {
    res.render("index.ejs")
})

server.get('/login', (req, res) => {
    res.render('login.ejs')
})

server.post('/login', passport.authenticate("local", {

    successRedirect: "/",
    failureRedirect: "/login",
    failureFlash: true
}))

server.get('/registration', (req, res) => {
    res.render('registration.ejs')
})

server.post('/registration', async(req, res) => {
    // console.log(req.body)
    const encryptedPassword = await bcrypt.hash(req.body.password.toString(), 10)
    const { firstName, lastName, email } = req.body
    console.log(firstName, lastName, email, encryptedPassword)
    if (email && encryptedPassword) {
        try {
            //db.promise().query(`INSERT INTO user (email, password, firstName, lastName) VALUES('${email}','${encryptedPassword}','${firstName}','${lastName}')`)
            const result = await db.user.create({
                data: { email: email, password: encryptedPassword, firstName: firstName, lastName: lastName }
            })
            console.log(result);
            //res.status(201).send({ message: "User is created" })
            res.redirect("/login")
        } catch (error) {
            console.log(error)
            res.redirect("/registration")
        } finally {
            await db.$disconnect();
        }

    }
})

main();

登录视图页面

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>Login</title>
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
        <style>
            .main {
                background-color: #EAF7FF;
                width: 100%;
                height: 100vh;
                margin: auto;
            }
            
            .form-container {
                background-color: rgb(255, 255, 255);
                max-width: 500px;
                margin: 0 auto;
                padding: 30px;
                border: 1px solid #ccc;
                border-radius: 10px;
                box-shadow: 0 0 10px #ccc;
            }
            
            .btn {
                background-color: #4F95FF;
                width: 100px;
                border-radius: 14px;
            }
        </style>
    </head>

    <body>
        <div class="main">
            <div class="form-container">
                <form action="/login" method="POST">
                    <h2 class="text-center">Login</h2>
                    <div class="form-group">
                        <input type="email" name="email" class="form-control" id="email" placeholder="Email">
                    </div>
                    <div class="form-group">
                        <input type="password" name="password" class="form-control" id="password" placeholder="Password">
                    </div>
                    <div class="form-group form-check">
                        <input type="checkbox" class="form-check-input" id="remember-me">
                        <label class="form-check-label" for="remember-me">Remember me</label>
                    </div>
                    <div class="text-center">
                        <button type="submit" class="btn btn-primary btn-rounded btn-lg">Login</button>
                    </div>
                    <div class="text-center">
                        <p>Don't have an account?
                            <a href="registration"> Register</p>
                </div>
            </form>
        </div>
        </div>
    </body>

</html>

排查方向与解决方法

  • 数据库字段长度问题:bcrypt生成的哈希值是60位字符串,检查MySQL中user表的password字段类型是否为VARCHAR(255)。如果字段长度不足,哈希值会被截断,导致对比失败。修改字段长度后,需要重新注册用户(旧数据的密码已被截断,无法正常验证)。
  • 注册过程的密码验证:在注册代码中添加日志,确认原始密码和哈希后的密码是否匹配,再核对数据库中存储的密码是否与日志中的哈希值一致:
    // 注册时临时添加日志
    const rawPassword = req.body.password;
    console.log('原始密码:', rawPassword);
    const encryptedPassword = await bcrypt.hash(rawPassword, 10);
    console.log('哈希后密码:', encryptedPassword);
    
    如果数据库中的密码和日志不一致,说明存储过程存在问题,检查Prisma的创建语句是否正确。
  • Prisma查询的密码准确性:在passport的authenticateUsers函数中,打印从数据库查询到的user.password,确认和数据库中存储的密码一致:
    const user = await getUserByEmail(email)
    console.log('数据库存储的密码:', user.password);
    
    如果不一致,检查schema.prisma中的User模型定义,确保password字段为String类型,且没有额外的转换逻辑。
  • 中间件顺序检查:确保session中间件在passport.initialize()和passport.session()之前加载,你的当前代码顺序是正确的,若之前调整过顺序需恢复。

内容的提问来源于stack exchange,提问作者Sami

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 05:30:53