好的,所以一般来说我不会像你想要的那样自定义身份验证回调中的错误消息。首先,如果您这样做,您将在每个身份验证调用中重复自己,其次,这与该中间件无关。
不过,我倾向于集中错误处理和消息传递,这是一个较长的讨论。
如果您真的想这样做,那么您需要确保req, res, next 在范围内,如下所示:
app.route('/login')
.get(function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) {
err.message = 'Incorrect username or password';
return next(err);
}
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/users/' + user.username);
});
})(req, res, next);
});
好的,至于集中错误处理,我通常采用的方法是创建自定义错误类,我可以根据需要对其进行实例化,然后在错误处理中间件中进行处理。这可以像其他任何东西一样轻松地应用于身份验证,并且您可以随着项目的增长逐步构建它们,所以它不会太难。例如,从一个自定义的 FailedLoginError 开始,我可能会做这样的事情(在 ES6 语法中,在旧的 JS 语法中并不难):
// ./lib/errors/failed-login-error.js
class FailedLoginError extends Error {
// You could set the message here if you wanted rather than letting the calling code set it
constructor(error, userMessage) {
super(error.message);
this.name = this.constructor.name;
this.previousError = error;
this.statusCode = 401;
this.userMessage = userMessage || 'You provided an incorrect username or password';
Error.captureStackTrace(this, this.constructor);
}
}
然后我会创建一个自定义中间件来包装 Passport 设置,这样我就不必每次都记得使用它。
// ./lib/middleware/authenticate.js
// Similar to the example above, we have an error that has a 500 status
const ServerError = require('../errors/internal-server-error');
const FailedLoginError = require('../errors/failed-login-error');
module.exports = (req, res, next) => {
passport.authenticate('jwt', { session: false }, (err, user, info) => {
// an exception happened trying to do the login
if (err) return next(new ServerError(err));
// user was not correct. Add more info to the error message if you want, like maybe the Username was incorrect or the Token was expired or whatever.
if (!user) return next(new FailedLoginError(err));
// we get here and the user logged in right
req.logIn(user, (e) => {
if (e) return next(ServerError(e));
return res.redirect('/users/' + user.username); // or whatever the right thing is here
});
});
});
好的,那么通过该设置,您现在可以设置一些利用自定义错误的错误处理中间件:
// ./lib/middleware/error-handler.js
module.exports = (err, req, res, next) {
// normalize the possibly missing status and userMessages
err.statusCode = err.statusCode || 500;
err.userMessage = err.userMessage || 'Something went wrong.';
// always log something; use something other than console.error if you like
// note here we're logging the real error message.
console.error(`${req.method} ${req.url} - ${err.statusCode} - ${err.message}`);
// next, give the user something you don't mind them seeing
res.status(err.statusCode).send(err.userMessage);
};
现在将所有这些放在一起,您的应用代码将简化为如下所示:
const errorHandler = require('./lib/middleware/error-handler');
const authenticate = require('./lib/middleware/authenticate');
// other requires as needed.
app.use(errorHandler);
app.route('/login')
.all(authenticate)
.get((req, res, next) => {
// whatever you want to do here, it's already got a user and so on.
});
我不久前整理了一个库,它使用这种模式并创建了一堆通用的 HTTP 错误类。它可能需要更新,但可能会给您一些启发。 https://github.com/pvencill/praeter