Отправка ответа JSON при сбое аутентификации Passport.js

извините, я очень новичок в node.js, так что я еще не смог обмануть голову. Я использую Node.js в качестве backend API-сервера для iPhone-клиента. Я использую Passport.js для проверки подлинности с помощью локальной страtagsи. Соответствующий код приведен ниже:

// This is in user.js, my user model UserSchema.static('authenticate', function(username, password, callback) { this.findOne({ username: username }, function(err, user) { if (err){ console.log('findOne error occurred'); return callback(err); } if (!user){ return callback(null, false); } user.verifyPassword(password, function(err, passwordCorrect){ if (err){ console.log('verifyPassword error occurred'); return callback(err); } if (!passwordCorrect){ console.log('Wrong password'); return callback(err, false); } console.log('User Found, returning user'); return callback(null, user); }); }); }); 

а также

 // This is in app.js app.get('/loginfail', function(req, res){ res.json(403, {message: 'Invalid username/password'}); }); app.post('/login', passport.authenticate('local', { failureRedirect: '/loginfail', failureFlash: false }), function(req, res) { res.redirect('/'); }); 

Прямо сейчас, мне удалось перенаправить неудачный вход в / loginfail, где я отправляю обратно JSON на iPhone-клиент. Однако это не имеет достаточной детализации. Я хочу, чтобы иметь возможность отправить обратно соответствующие ошибки для iPhone-клиента, такие как: «Нет пользователей» или «Пароль неправильный». С моим существующим кодом я не вижу, как это можно сделать.

Я попытался следовать примерам для пользовательского обратного вызова на сайте passport.js, но я просто не могу заставить его работать из-за отсутствия понимания узла. Как мне изменить свой код, чтобы я мог отправить обратно res.json с соответствующим кодом ошибки / сообщением?

EDIT: Я сейчас пытаюсь сделать что-то вроде этого:

 // In app.js app.post('/login', function(req, res, next) { passport.authenticate('local', function(err, user, info) { if (err) { return next(err) } if (!user) { console.log(info); // *** Display message without using flash option // re-render the login form with a message return res.redirect('/login'); } console.log('got user'); return res.json(200, {user_id: user._id}); })(req, res, next); }); // In user.js UserSchema.static('authenticate', function(username, password, callback) { this.findOne({ username: username }, function(err, user) { if (err){ console.log('findOne error occurred'); return callback(err); } if (!user){ return callback(null, false); } user.verifyPassword(password, function(err, passwordCorrect){ if (err){ return callback(err); } if (!passwordCorrect){ return callback(err, false, {message: 'bad password'}); } console.log('User Found, returning user'); return callback(null, user); }); }); }); 

Но назад, когда я пытаюсь console.log (info), он просто говорит undefined. Я не знаю, как заставить этот пользовательский обратный вызов работать … Любая помощь будет оценена по достоинству!

Я считаю, что функция обратного вызова, которую ваши «аутентифицирующие» статические вызовы (называемые «обратным вызовом» в вашем коде) принимают третий параметр – «информация», который может предоставить ваш код. Затем вместо передачи в объект {failRedirect: …} передайте функцию, которая принимает 3 аргумента – err, user и info. «Информация», предоставленная вами в вашем методе проверки подлинности, будет передана этому обратному вызову.

Паспорт вызывает этот сценарий «пользовательский обратный вызов». См. Документы здесь: http://passportjs.org/guide/authenticate/

У меня была аналогичная проблема с паспортом и ошибками входа в систему. Я создавал API и хотел, чтобы все ответы были возвращены как JSON. Паспорт отвечает на недействительный пароль со статусом: 401 и тело: «Неавторизованный». Это всего лишь текстовая строка в теле, а не JSON, поэтому она сломала мой клиент, который ожидал всех JSON.

Как оказалось, есть способ заставить Passport просто вернуть ошибку в структуру вместо того, чтобы пытаться отправить ответ сам.

Ответ заключается в том, чтобы установить failWithError в параметрах, переданных для проверки подлинности: https://github.com/jaredhanson/passport/issues/126#issuecomment-32333163

Из комментария Джаредхансона в выпуске:

 app.post('/login', passport.authenticate('local', { failWithError: true }), function(req, res, next) { // handle success if (req.xhr) { return res.json({ id: req.user.id }); } return res.redirect('/'); }, function(err, req, res, next) { // handle error if (req.xhr) { return res.json(err); } return res.redirect('/login'); } ); 

Это вызовет обработчик ошибок после вызова Passport next(err) . Для моего приложения я написал общий обработчик ошибок, специфичный для моего случая использования, просто предоставляя ошибку JSON:

 // Middleware error handler for json response function handleError(err,req,res,next){ var output = { error: { name: err.name, message: err.message, text: err.toString() } }; var statusCode = err.status || 500; res.status(statusCode).json(output); } 

Затем я использовал его для всех маршрутов api:

 var api = express.Router(); ... //set up some routes here, attached to api ... // error handling middleware last api.use( [ handleError ] ); 

Я не нашел параметр failWithError в документации. Я наткнулся на него, прослеживая код в отладчике.

Кроме того, прежде чем я понял это, я попробовал «пользовательский обратный вызов», упомянутый в ответе @Kevin_Dente, но это не сработало для меня. Я не уверен, что это было для более старой версии Паспорта или если я просто делал это неправильно.

Существует официальная документация для пользовательского обратного вызова :

 app.get('/login', function(req, res, next) { passport.authenticate('local', function(err, user, info) { if (err) { 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); }); 

https://github.com/passport/www.passportjs.org/blob/master/views/docs/authenticate.md

Вы можете сделать это без пользовательских обратных вызовов, используя свойство «passReqToCallback» в определении страtagsи:

 passport.use(new LocalStrategy({passReqToCallback: true}, validateUserPassword)); 

Затем вы можете добавить свой собственный код ошибки аутентификации в запрос в коде страtagsи:

 var validateUserPassword = function (req, username, password, done) { userService.findUser(username) .then(user => { if (!user) { req.authError = "UserNotFound"; return done(null, false); } 

И, наконец, вы можете обрабатывать эти пользовательские ошибки на своем маршруте:

 app.post('/login', passport.authenticate('local', { failWithError: true }) function (req, res) { .... }, function(err, req, res, next) { if(req.autherror) { res.status(401).send(req.autherror) } else { .... } } );