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

Passport Local策略下登录失败后可绕过认证访问受保护路由的问题

问题分析与修复方案

核心问题

登录失败后仍能访问受保护路由的根源在于:

  • 登录路由中提前调用了req.login(),该方法会直接将用户对象序列化到会话中,使req.isAuthenticated()返回true。即便后续passport.authenticate('local')验证密码失败,会话已被标记为“已认证”,导致受保护路由的校验逻辑失效。
  • 注册路由存在语法错误,导致注册后未正确完成认证流程。
  • 存在重复的/submit POST路由,会覆盖前一个路由逻辑。

修复步骤

1. 修正登录路由逻辑

删除提前调用的req.login(),直接用passport.authenticate处理认证,失败时重定向回登录页:

app.post('/login', passport.authenticate('local', {
  successRedirect: '/restricted',
  failureRedirect: '/login'
}), (req, res) => {});

如果需要自定义失败处理逻辑,可使用回调形式:

app.post('/login', (req, res, next) => {
  passport.authenticate('local', (err, user) => {
    if (err) return next(err);
    if (!user) return res.redirect('/login');
    
    req.login(user, (err) => {
      if (err) return next(err);
      res.redirect('/restricted');
    });
  })(req, res, next);
});

2. 修复注册路由的语法错误

原代码中passport.authenticate('local'), (req, res, function() {的逗号为语法错误,且注册成功后需手动调用req.login完成登录:

app.post('/register', (req, res) => {
  User.register({username: req.body.username}, req.body.password, function(err, user) {
    if (err) {
      console.log(err);
      return res.redirect('/register');
    }
    
    req.login(user, (err) => {
      if (err) {
        console.log(err);
        return res.redirect('/register');
      }
      res.redirect('/restricted');
    });
  });
});

3. 删除重复的/submit路由

原代码中有两个完全相同的app.post('/submit'),删除其中一个,并添加重定向反馈:

app.post('/submit', async (req, res) => {
  try {
    await User.findOneAndUpdate({_id: req.user.id}, {$push: {'secrets': req.body.secretToPost}});
    res.redirect('/restricted');
  } catch (err) {
    console.log(err);
    res.redirect('/submit');
  }
});

4. 可选:封装认证中间件(优化代码复用)

避免重复编写req.isAuthenticated()校验,统一用中间件保护路由:

function isAuthenticated(req, res, next) {
  if (req.isAuthenticated()) return next();
  res.redirect('/login');
}

// 使用中间件保护路由
app.get('/restricted', isAuthenticated, async (req, res) => {
  try {
    const foundUsers = await User.find({'secrets': {$ne: []}});
    res.render('restricted', {usersWithSecrets: foundUsers});
  } catch(err) {
    console.log(err);
  }
});

app.get('/submit', isAuthenticated, (req, res) => {
  res.render('submit');
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 19:23:12