我已经像这样配置了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
中的请求/响应我不确定如何回复。
答案 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.' });