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

Mongoose从回调改Promise后,Passport的done函数失效致登录认证异常

问题:Mongoose改用Promise后Passport认证无法传递用户至req.user

由于Mongoose不再支持回调,我正在重构代码。虽然findOne()能找到用户,但无法将用户传递到routes.js中,导致isLoggedIn函数无法正常工作(req.user为undefined)。


旧代码:routes.js(isLoggedIn函数异常)

app.post('/login', passport.authenticate('local-login', {
    successRedirect : '/profile', // 重定向到安全的个人资料页面
    failureRedirect : '/login', // 出错时重定向回登录页
    failureFlash : true // 允许使用flash消息
}));

// 使用路由中间件验证用户是否登录(isLoggedIn函数)
app.get('/profile', isLoggedIn, function(req, res) {
    res.render('pages/profile.ejs', {
        user : req.user // 从会话中取出用户并传递给模板
    });
});

// 验证用户是否登录的路由中间件
function isLoggedIn(req, res, next) {
    console.log("这里应该打印req.user,但它是undefined");
    console.log(req.user);
    // 如果用户已在会话中认证,继续执行
    if (req.isAuthenticated()){
        return next();
    }
    // 未认证则重定向到首页
    res.redirect('/');
}

旧代码:passport.js

passport.use('local-login', new LocalStrategy({
    // 默认本地策略用用户名和密码,这里替换为邮箱
    usernameField : 'email',
    passwordField : 'password',
    passReqToCallback : true // 允许将整个请求传递给回调函数
},
function(req, email, password, done) { // 表单传来的邮箱和密码作为回调参数
    User.findOne({ 'local.email' :  email }, function(err, user) {
        console.log("正在查找用户");
        // 有错误先返回错误
        if (err)
            return done(err);

        // 未找到用户,返回提示消息
        if (!user)
            return done(null, false, req.flash('loginMessage', '未找到该用户。')); // req.flash是用connect-flash设置闪存数据的方式

        // 用户存在但密码错误
        if (!user.validPassword(password))
            return done(null, false, req.flash('loginMessage', '哎呀!密码错误。')); // 创建loginMessage并存入会话闪存

        // 一切正常,返回认证成功的用户
        return done(null, user);
    });

}));

重构后的passport.js(done()无法正常执行,认证失败)

passport.use('local-login', new LocalStrategy({
    // 默认本地策略用用户名和密码,这里替换为邮箱
    usernameField : 'email',
    passwordField : 'password',
    passReqToCallback : true // 允许将整个请求传递给回调函数
},
function(req, email, password, done) { // 表单传来的邮箱和密码作为回调参数
    console.log(email + " 尝试登录");

    // 查找邮箱与表单输入一致的用户
    // 检查尝试登录的用户是否已存在
    User.findOne({ 'local.email' :  email })
    .then(user=>{
         if (!user){
            return done(null, false, req.flash('loginMessage', '未找到该用户。')); // req.flash是用connect-flash设置闪存数据的方式
         }
         if (!user.validPassword(password)){
             return done(null, false, req.flash('loginMessage', '哎呀!密码错误。')); // 创建loginMessage并存入会话闪存
         }
       req.user= user;
        return user;     
    })
    .then(user=>done(null,user))
    .catch((err)=>{
        return done(null, false);
req.flash('loginMessage', '未找到该用户。')); // req.flash是用connect-flash设置闪存数据的方式
    });

}));

问题分析与修复方案

你的新代码存在三个关键问题:

  1. 重复调用done():第一个then分支已经在用户不存在/密码错误时调用了done(),后续then又重复调用,导致Passport逻辑混乱。
  2. 错误处理语法错误+逻辑错误:catch块存在语法错误(多余闭合括号),且错误发生时未将err传递给done(),无法正确触发Passport的错误处理流程。
  3. 手动赋值req.user无效:Passport会在认证成功后自动处理req.user的赋值和会话存储,手动设置反而可能干扰流程。

修复后的passport.js代码

passport.use('local-login', new LocalStrategy({
    usernameField : 'email',
    passwordField : 'password',
    passReqToCallback : true
},
async function(req, email, password, done) { // 改用async/await简化逻辑
    console.log(`${email} 尝试登录`);
    try {
        const user = await User.findOne({ 'local.email': email });
        
        if (!user) {
            return done(null, false, req.flash('loginMessage', '未找到该用户。'));
        }
        
        if (!user.validPassword(password)) {
            return done(null, false, req.flash('loginMessage', '哎呀!密码错误。'));
        }
        
        // 认证成功,返回用户,Passport自动处理会话与req.user赋值
        return done(null, user);
    } catch (err) {
        // 传递数据库错误给Passport
        return done(err);
    }
}));

修复说明

  • 用async/await替代Promise链式调用,避免链式调用的嵌套陷阱,代码更易维护。
  • 移除无效的req.user = user赋值,交给Passport自动处理用户会话与req.user的绑定。
  • 每个分支仅调用一次done(),避免重复调用导致的认证逻辑冲突。
  • 错误处理时直接传递err给done(),让Passport正确捕获并处理数据库异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 11:35:34