如何使用 Express 和 PassportJS 正确报告无效登录?

Posted

技术标签:

【中文标题】如何使用 Express 和 PassportJS 正确报告无效登录?【英文标题】:How can I report an invalid login properly with Express and PassportJS? 【发布时间】:2012-03-30 05:38:27 【问题描述】:

我已成功在我的 Express/Mongoose 网络应用中实现了本地护照,但我无法弄清楚如何正确呈现失败的登录消息。

这是我的登录路径:

app.get('/login', function(req, res) 
   res.render('user/login', 
   );
);

使用这样的路由,我应该如何报告无效登录?如果登录成功,它会将id/username 写入req.user 对象,但这对"GET /login" 路由没有帮助,因为如果登录成功,您将被重定向到您想去的页面.

这意味着当您GET 登录页面时,req.user 将始终是undefined

我希望能够写出一条消息,例如“哟,登录无效!”当以下情况发生时:

    用户不存在。 提供的密码不匹配,但用户存在。

我可能想根据发生的情况输出不同的消息。

当我实现 LocalStrategy 时,我使用了以下代码:

passport.use(new LocalStrategy(
    usernameField: 'email'
,
function(email, password, fn) 
  User.findOne('login.email': email, function(err, user) 
    // Error was thrown.
    if (err) 
      return fn(err);
    

    // User does not exist.
    if (!user) 
      return fn(null, false);
    

    // Passwords do not match.
    if (user.login.password != utility.encryptString(user.login.salt + password)) 
      return fn(null, false);
    

    // Everything is good.
    return fn(null, user);
  );

));

正如您所见,存在一些问题,但这就是 PassportJS 的作者设置他的应用程序的方式。我们应该如何访问 Strategy 返回的内容?

如果它抛出一个错误,我什至应该调用什么来访问err

谢谢。

【问题讨论】:

【参考方案1】:

在最新版本的 Passport 中,我添加了对 flash 消息的支持,这使您可以轻松地完成您的要求。

您现在可以向done 提供第三个参数,其中可以包含失败消息。例如:

if (user.login.password != utility.encryptString(user.login.salt + password)) 
  return fn(null, false,  message: 'yo, invalid login!' );

然后,将failureFlash 设置为true 作为authenticate() 的选项。

passport.authenticate('local',  successRedirect: '/',
                                 failureRedirect: '/login',
                                 failureFlash: true );

在这种情况下,如果认证失败,消息会被设置在flash中,供你再次显示登录页面时渲染。

自定义回调也非常好。内置选项只是让完成常见任务变得更简单。

另外,我很好奇:您提到样本存在问题。你认为应该改进什么?我想让这些例子尽可能好。谢谢!

(有关更多详细信息,请参阅问题 #12 上的 comment)。

【讨论】:

故障闪现让它变得容易多了。但是,我确实注意到传递给done 的任何err 或OP 的fn 对于该工作必须为null 或false - 我花了一分钟才意识到这一点。【参考方案2】:

您可以使用自定义回调或中间件功能来获得更多控制权。有关示例,请参阅指南的 Authentication 部分。

例如,自定义回调可能如下所示:

app.get('/login', function(req,res,next) 
    passport.authenticate('local', function(err,user) 
            if(!user) res.send('Sorry, you\'re not logged in correctly.');
            if(user) res.send('Skeet skeet!');
    )(req,res,next);
);

或者,您始终可以重定向两个响应:

app.get('/login', 
    passport.authenticate('local',  successRedirect: '/winner',
                                     failureRedirect:'/loser' ));

或者用简单的中间件重定向失败:

app.get('/login', ensureAuthenticated,
    function(req,res) 
                // successful auth
                // do something for-the-win
    
);

    // reusable middleware
    function ensureAuthenticated(req,res,next) 
        if(req.isAuthenticated()) return next();
        res.redirect('/login/again'); // if failed...
    

【讨论】:

不错,自定义回调方法看起来可行。谢谢。两种替代解决方案如何做同样的事情呢?您不会在 POST 请求上执行成功/失败重定向示例吗?这就是我正在做的。第二种选择只是强制登录以访问页面的标准方法?就像,这就是您要在想要控制访问的页面上放置的内容(用户配置文件等)。我将把你标记为自定义回调的答案。 我认为您的问题是“我如何响应身份验证成功或失败?”,这三种方法是不同的方法。对于替代方案,您只是将客户端发送到不同的路线来处理响应......因为我不知道您的实施细节,所以由您决定什么是最好的。是的,选项 3 是对需要身份验证的页面强制执行身份验证的好方法。

以上是关于如何使用 Express 和 PassportJS 正确报告无效登录?的主要内容,如果未能解决你的问题,请参考以下文章

Express + PassportJS 无法读取 flash 消息

Express 会话和 PassportJS 之间的区别

Express 会话与 PassportJS 会话

在 React/Express 中使用 PassportJS 进行 Google OAuth 时出现 CORS 错误

PassportJS:如何在我的视图中获取 req.user

使用 Passportjs 刷新页面后保持身份验证