Хорошо, поэтому в общем Я бы не стал настраивать сообщение об ошибке в обратном вызове аутентификации, как вы хотите. Во-первых, вы будете повторяться при каждом вызове аутентификации, а во-вторых, это не касается промежуточного программного обеспечения.
Я склонен централизовать обработку ошибок и обмен сообщениями, однако это более длительное обсуждение.
Если вы действительно хотите это сделать, то вам нужно убедиться, что 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