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

Node.js+Passport登录始终跳转至failureRedirect问题求助

Node.js + Passport 本地登录始终跳转到failureRedirect的问题

我用Node.js搭建后端,结合Passport实现简单登录页面,代码逻辑看似没问题,甚至ChatGPT也没检测出错误,但无论输入正确与否,都会跳转到failureRedirect路由。我已确认邮箱和密码正确(测试用3位简单密码,数据库中哈希后的密码也核对过)。

实现思路:用户提交的密码加盐哈希后存入数据库,通过Passport本地策略对比表单输入与数据库数据,匹配则跳转至指定页面,否则跳转至另一页面(仅作测试)。以下是相关代码:

User 模型

// my User model, exported correctly
const UserSchema = new Schema({
    firstName: {type: String, required: true},
    lastName: {type: String, required: true},
    email: {type: String, required: true},
    password: {type: String, required: true},
    posts: {type: Schema.Types.ObjectId, ref: "Post"}
})

密码哈希与用户注册逻辑

// password hashing code & user creation
asyncHandler(async (req, res, next) => {
    try {
        // Hash the password
        const hashedPassword = await bcrypt.hash(req.body.password, 10);

        // Check if user with the provided email already exists
        const existingUser = await User.findOne({ email: req.body.email }).exec();

        if (existingUser) {
            return res.status(400).send('Email already exists. Please use a different one.');
        }

        // Create new user
        const user = new User({
            firstName: req.body.firstName,
            lastName: req.body.lastName,
            email: req.body.email,
            password: hashedPassword // Use the hashed password
        });

        await user.save();

        // Redirect after successful registration
        res.redirect("/");
    } catch (err) {
        next(err);
    }
});

Passport 认证策略配置

// snippet of my authentication 
function configurePassport(passport) {
    passport.use(new LocalStrategy( async (email, password, done) => {
      try {
        const user = await User.findOne({ email: email })
        if (!user) {
          // usernames do not match!
          return done(null, false, { message: "Incorrect username" })
        };
        const match = await bcrypt.compare(password, user.password)
        if (!match) {
            // passwords do not match!
            return done(null, false, { message: "Incorrect password" })
          }
        return done(null, user);
      } catch(err) {
        return done(err);
      };
    }));
}

登录页面模板(Pug)

h1= title
if user 
  h1 Welcome back #{user.firstName}
else  
  form(action="/", method="post")  
    input(type="email", name="email", placeholder="email")
    input(type="password", name="password", placeholder="password")
    button(type="submit") Log In
  a(href="/register") Register Now

认证中间件配置

passport.authenticate("local", {
    successRedirect: "/",
    failureRedirect: "/register"
});

我已尝试多种方法仍未定位问题,应用逻辑简单,推测是某处细节失误。configurePassport函数已在主应用中正确调用。


问题排查关键点

  1. LocalStrategy 字段映射缺失
    Passport LocalStrategy默认会从请求体中读取username和password字段,但你的登录表单用email作为用户名标识,必须显式指定字段映射,否则策略会找不到正确的邮箱值,导致查不到用户直接返回失败:
passport.use(new LocalStrategy({
    usernameField: 'email', // 指定使用email作为用户名字段
    passwordField: 'password'
}, async (email, password, done) => {
    // 原逻辑代码
}));
  1. 表单路由与认证中间件的绑定
    确认登录表单提交的action="/"对应的POST路由,正确挂载了Passport认证中间件,且中间件顺序正确(必须在express.urlencoded()之后,否则无法解析表单数据):
// 先解析表单数据
app.use(express.urlencoded({ extended: true }));
// 再挂载登录路由
app.post('/', passport.authenticate('local', {
    successRedirect: '/',
    failureRedirect: '/register'
}));
  1. bcrypt 哈希一致性检查
  • 确认注册时使用的bcrypt.hash和登录时的bcrypt.compare版本一致,不同版本可能存在哈希格式兼容问题;
  • 注册时打印hashedPassword,和数据库中存储的密码对比,确保确实存入了哈希值而非明文或空值。
  1. 添加日志定位问题
    在LocalStrategy中添加日志,直接查看关键变量的值,快速定位是查不到用户还是密码不匹配:
passport.use(new LocalStrategy({ usernameField: 'email' }, async (email, password, done) => {
  try {
    console.log('收到的登录邮箱:', email);
    console.log('收到的登录密码:', password);
    const user = await User.findOne({ email: email })
    console.log('查询到的用户:', user);
    if (!user) {
      return done(null, false, { message: "Incorrect username" })
    };
    const match = await bcrypt.compare(password, user.password)
    console.log('密码匹配结果:', match);
    if (!match) {
        return done(null, false, { message: "Incorrect password" })
      }
    return done(null, user);
  } catch(err) {
    console.log('认证过程报错:', err);
    return done(err);
  };
}));
  1. Passport 序列化/反序列化配置
    如果未配置序列化和反序列化逻辑,即使登录成功也无法维持会话,虽不会直接导致跳failureRedirect,但会影响后续用户状态判断,需确认配置:
passport.serializeUser((user, done) => {
    done(null, user.id);
});

passport.deserializeUser(async (id, done) => {
    try {
        const user = await User.findById(id);
        done(null, user);
    } catch (err) {
        done(err);
    }
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 21:20:29