如何处理passport.deserializeUser()中的错误?

时间:2016-12-09 22:03:42

标签: javascript node.js passport.js

我已经像这样配置了Express和Passport:

var express = require("express");
var site = express();
var flash = require("connect-flash");
var passport = require("passport");

site.use(require("cookie-parser")());
site.use(require("body-parser").urlencoded({extended:false}));
site.use(require("express-session")(...));
site.use(flash());
site.use(passport.initialize());
site.use(passport.session());

我有一个非常好的库存实现deserializeUser(我正在通过Bookshelf使用MySQL支持的local身份验证):

var db = require("./database.js"); // exports models e.g. db.User

passport.deserializeUser(function(id, done) {
    db.User.findById(id).then(function (user) {
        done(null, user);
    }).catch(function (err) {
        done(err, null);
    });
});

我遇到了以下特定问题:当从数据库中删除登录用户时(例如,当站点管理员删除用户时),反序列化失败,正如所料,{{1}来自Bookshelf。但是,我不知道如何处理它; CustomError("EmptyResponse")最终只会导致错误消息和堆栈跟踪以HTML格式发送回客户端。

问题是:如何在失败时从done(err, null)提供自定义,优雅的错误处理?

现在,如果它简化了一些事情,我可以在deserializeUser调用中添加{require:false}给我一个db.User.findById用户而不是错误,但我仍然不知道如何处理它(我还需要处理错误对象,例如,如果数据库服务器已关闭并且存在连接错误)。

我想要失败的操作是将用户重定向回登录页面,可能带有描述性的flash消息,但我无法访问null中的请求/响应我不确定如何回复。

2 个答案:

答案 0 :(得分:7)

我找到了一个解决方案。这里的错误可以在Express中间件错误处理程序中处理。所以,例如:

// Note: Must be used *after* passport middleware.
site.use(function(err, req, res, next) {
    if (err) {
        // Handle deserialization errors here.
    } else {
        next();
    }
});

一个重要的警告是,如果反序列化失败不可恢复,通过护照访问的所有路由(即使是那些不需要身份验证的路径)将继续失败,最有可能还包括您的登录和注销端点,从而永久中断访问,直到用户清除其Cookie 。因此,您必须强制退出,这是唯一真正的恢复方式:

site.use(function(err, req, res, next) {
    if (err) {
        req.logout(); // So deserialization won't continue to fail.
    } else {
        next();
    }
});

进一步构建,在我的情况下,我想通过flash消息重定向回登录页面。但是你必须要小心:如果登录页面本身发生错误,你需要避免无限重定向,所以:

site.use(function(err, req, res, next) {
    if (err) {
        req.logout();
        if (req.originalUrl == "/loginpage") {
            next(); // never redirect login page to itself
        } else {
            req.flash("error", err.message);
            res.redirect("/loginpage");
        }
    } else {
        next();
    }
});

当然,您可能只想对CustomError("EmptyResponse")执行此操作,或者甚至重做反序列化实现中的错误处理,以使其抛出您自己更具体的错误。

有点奇怪的方法,但似乎完成了工作。提供更清晰的建议。

答案 1 :(得分:0)

Passport docs "Configure" section中,它们显示了发送特定消息的能力:

<ul id="states">
  <li><a href="#">Alabama</a></li>
  <li><a href="#">Alaska</a></li>
  <li><a href="#">Arizona</a></li>
  <li><a href="#">Arkansas</a></li>
  <li><a href="#">California</a></li>
</ul>


<div id="main">Main</div>

以上示例在他们的文档中,但在您的情况下,您可以执行以下操作:

return done(null, false, { message: 'Incorrect username.' });