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

Node.js passport认证failureRedirect登录失败不跳转无限加载问题

问题现象
  • 正确账号密码登录流程运行正常
  • 输入正确邮箱、错误密码提交登录时,页面无限加载,未按照failureRedirect配置跳转回登录页

原有代码参考

server.js

require('dotenv').config();
const express = require('express');
const app = express();
const passport = require('passport');
const initializePassport = require('./passport-config');
const session = require('express-session');
const methodOverride = require('method-override');
initializePassport(
    passport,
    async email=>{
        try{
            let bookshelfUser = await createBookshelfOf("User");
            return await new bookshelfUser().where("email", email).fetch().then((data)=>{
                return data.attributes;
            });
        }
        catch (e) {
            console.log(e);
            return null;
        }},
    async id=>{
        try{
            let bookshelfUser = await createBookshelfOf("User");
            return await new bookshelfUser().where("id", id).fetch().then((data)=>{
                return data.attributes;
            });
        }
        catch (e) {
            return null;
        }});
app.post('/login', passport.authenticate('local', {
        successRedirect : '/',
        failureRedirect  : '/login',
    })
);

passport-config.js

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

function initialize(passport, getUserByEmail, getUserById) {
    console.log("Passport initialized");
    const authenticateUser = async (email, password, done) => {
        const user = await getUserByEmail(email);
        if (user == null) {
            console.log("No user with that email");
            return done(null, false, { message: 'No user with that email' });
        }

        try {
            await bcrypt.compare(password, user.geslo, (err, result)=>{
                if (err){
                    console.log("Password incorrect");
                    return done(null, false, { message: 'Password incorrect' });
                }
                if(result){
                    console.log("User logged in successfully: " + user.username);
                    return done(null, user);
                }
            });
        } catch (e) {
            console.log(e);
            return done(e)
        }
    }

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

module.exports = initialize
问题根因

核心问题出在passport-config.js的密码比对逻辑:

  1. 分支覆盖不全:bcrypt.compare的回调里仅处理了比对报错、比对成功两个场景,当密码错误result === false时,没有调用Passport要求的done()回调,Passport始终收不到认证结果,请求会一直挂起,最终表现为页面无限加载
  2. 逻辑理解错误:bcrypt.compare回调中的err参数仅代表比对过程出现系统异常(比如哈希值格式非法),不是密码错误的标识,原代码把系统异常直接判定为密码错误,会掩盖真实的运行报错
  3. 写法不规范:混用async/await和回调函数写法,容易出现逻辑遗漏
修复方案

修改passport-config.js中的authenticateUser方法,统一使用async/await写法,补全所有分支的done()调用:

const authenticateUser = async (email, password, done) => {
    const user = await getUserByEmail(email);
    if (user == null) {
        console.log("No user with that email");
        return done(null, false, { message: 'No user with that email' });
    }

    try {
        // 直接await获取比对结果,不传入回调
        const isPasswordMatch = await bcrypt.compare(password, user.geslo);
        if (isPasswordMatch) {
            console.log("User logged in successfully: " + user.username);
            return done(null, user);
        }
        // 补全密码不匹配的分支,必须调用done返回认证失败结果
        console.log("Password incorrect");
        return done(null, false, { message: 'Password incorrect' });
    } catch (e) {
        console.log(e);
        return done(e);
    }
}
补充配置检查

你贴出的server.js缺少几个Express和Passport的必要中间件,如果实际代码中也没配置,后续可能出现参数解析失败、会话不生效等问题,请在路由定义前补充以下代码:

// 解析POST表单参数
app.use(express.urlencoded({ extended: false }));
// 配置session(secret请替换为你自己的环境变量值)
app.use(session({
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: false
}));
// 初始化Passport
app.use(passport.initialize());
app.use(passport.session());
// 注册methodOverride中间件
app.use(methodOverride('_method'));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 21:03:18