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

我有Express和Passport这样configuration:

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的股票实现(我使用MySQL支持的local身份validation通过Bookshelf):

 var db = require("./database.js"); // exports models eg db.User passport.deserializeUser(function(id, done) { db.User.findById(id).then(function (user) { done(null, user); }).catch(function (err) { done(err, null); }); }); 

我遇到了以下特定问题:当从数据库中删除login用户(例如,当站点pipe理员删除用户时),反序列化会失败,如预期的那样, CustomError("EmptyResponse")书架。 但是,我不知道如何处理。 done(err, null)最终只会导致错误消息和堆栈跟踪以HTML格式返回给客户端。

问题是: 如何从deserializeUser提供自定义,优雅的error handling?

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

我想在失败的行动是redirect用户回login页面,可能与一个描述性的Flash消息,但我没有任何访问deserializeUser请求/响应,我不知道如何沟通背部。

我想出了一个解决scheme。 这里的错误可以在Express中间件error handling程序中处理。 所以,例如:

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

但是,一个重要的警告是,如果反序列化不可恢复, 所有通过护照访问的路由(即使是不需要authentication的路由)都将继续失败, 这很可能还包括您的login和注销端点,从而永远打破访问,直到用户清除他们的cookies 。 所以你必须强制注销,这是唯一真正的恢复方法:

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

进一步build设,在我的情况下,我想重新回到login页面的一个Flash消息。 但是你必须小心:如果login页面本身发生错误,你需要避免无限的redirect,所以:

 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")做这个,或者甚至在你的反序列化实现中重做error handling,让它抛出你自己更具体的错误。

一种奇怪的方法,但似乎完成工作。 打开更干净的build议。

在护照文档“configuration”部分 ,它们显示发送特定消息的能力:

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

上面的例子是在他们的文档中,但在你的情况下,你可以做一些事情:

 passport.deserializeUser(function(id, done) { db.User.findById(id).then(function (user) { done(null, user); }).catch(function (err) { done(err, null, { message: 'User does not exist' }); }); });