如何处理 passport.deserializeUser() 中的错误?
How do I handle errors in passport.deserializeUser()?
我已经像这样配置了 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
实现(我正在使用 MySQL 通过 Bookshelf 支持的 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);
});
});
我 运行 遇到以下具体问题:当登录用户从数据库中删除时(发生在例如站点管理员删除用户时),反序列化如预期的那样失败,来自 Bookshelf 的 CustomError("EmptyResponse")
。但是,我不知道如何处理它; done(err, null)
最终只会导致错误消息和堆栈跟踪作为 HTML 发送回客户端。
问题是:如何在失败时从 deserializeUser
提供自定义的、优雅的错误处理?
现在,如果它简化了事情,我可以将 {require:false}
添加到 db.User.findById
调用中给我一个 null
用户而不是错误,但我仍然不知道如何处理它(而且我仍然需要处理错误对象,例如,如果数据库服务器已关闭并且存在连接错误)。
我想在失败时采取的行动是将用户重定向回登录页面,可能带有描述性的快速消息,但我无权访问 [=13] 中的 request/response =] 而且我不确定如何回复。
在Passport docs "Configure" section中,它们显示了发送特定消息的能力:
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' });
});
});
我想出了一个解决办法。这里的错误可以在 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();
}
});
在此基础上进一步构建,在我的例子中,我想用一条闪现消息重定向回登录页面。但是你必须小心:如果登录页面本身发生错误,你需要避免无限重定向,所以:
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")
执行此操作,或者甚至在反序列化实现中重做错误处理,让它抛出您自己的更具体的错误。
有点奇怪的方法,但似乎可以完成工作。接受更清洁的建议。
我已经像这样配置了 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
实现(我正在使用 MySQL 通过 Bookshelf 支持的 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);
});
});
我 运行 遇到以下具体问题:当登录用户从数据库中删除时(发生在例如站点管理员删除用户时),反序列化如预期的那样失败,来自 Bookshelf 的 CustomError("EmptyResponse")
。但是,我不知道如何处理它; done(err, null)
最终只会导致错误消息和堆栈跟踪作为 HTML 发送回客户端。
问题是:如何在失败时从 deserializeUser
提供自定义的、优雅的错误处理?
现在,如果它简化了事情,我可以将 {require:false}
添加到 db.User.findById
调用中给我一个 null
用户而不是错误,但我仍然不知道如何处理它(而且我仍然需要处理错误对象,例如,如果数据库服务器已关闭并且存在连接错误)。
我想在失败时采取的行动是将用户重定向回登录页面,可能带有描述性的快速消息,但我无权访问 [=13] 中的 request/response =] 而且我不确定如何回复。
在Passport docs "Configure" section中,它们显示了发送特定消息的能力:
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' });
});
});
我想出了一个解决办法。这里的错误可以在 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();
}
});
在此基础上进一步构建,在我的例子中,我想用一条闪现消息重定向回登录页面。但是你必须小心:如果登录页面本身发生错误,你需要避免无限重定向,所以:
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")
执行此操作,或者甚至在反序列化实现中重做错误处理,让它抛出您自己的更具体的错误。
有点奇怪的方法,但似乎可以完成工作。接受更清洁的建议。