// 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?
编辑:我现在正在尝试这样的事情:// 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)时,它只是说未定义。我不知道如何让这个自定义回调工作...任何帮助将不胜感激!
答案 0 :(得分:57)
我遇到了与Passport类似的问题,并且登录响应失败。我正在构建一个API,并希望所有响应都以JSON的形式返回。 Passport响应无效密码,状态为:401和正文:"未授权"。这只是一个正文中的文本字符串,而不是JSON,所以它打破了我的客户端,它预计所有的JSON。
事实证明,有一种方法可以让Passport将错误返回到框架,而不是尝试自己发送响应。
答案是在传递给身份验证的选项中设置failWithError
:
https://github.com/jaredhanson/passport/issues/126#issuecomment-32333163
来自jaredhanson在该问题上的评论:
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
选项。我在跟踪调试器中的代码时偶然发现了它。
另外,在我弄清楚这一点之前,我尝试了#34;自定义回调"在@Kevin_Dente的答案中提到,但它对我没用。我不确定这是用于较旧版本的Passport还是我做错了。
答案 1 :(得分:27)
我相信你的'authenticate'静态调用的回调函数(代码中称为'callback')接受第三个参数 - “info” - 你的代码可以提供。然后,传入一个带有3个参数的函数 - 错误,用户和信息,而不是传入{failureRedirect:...}对象。您在身份验证方法中提供的“信息”将传递给此回调。
Passport将此方案称为“自定义回调”。请参阅此处的文档: http://passportjs.org/guide/authenticate/
答案 2 :(得分:3)
有自定义回调的官方文档:
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
答案 3 :(得分:1)
您可以在策略定义中使用属性“passReqToCallback”进行自定义回调时执行此操作:
passport.use(new LocalStrategy({passReqToCallback: true}, validateUserPassword));
然后,您可以在策略代码中将自定义身份验证错误代码添加到请求中:
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 {
....
}
}
);
答案 4 :(得分:0)
根据class MyMixInClass:
def __init__(self):
initfunc = getattr(super(), '__init__')
# can we figure out which class the __init__ came from?
的官方文档,您可以使用custom callback函数来处理授权失败的情况并覆盖默认消息。
如果您正在开发REST API,那么您将希望发出如下所示的JSON响应:
Passport
我正在使用{
"error": {
"name": "JsonWebTokenError",
"message": "invalid signature"
},
"message": "You are not authorized to access this protected resource",
"statusCode": 401,
"data": [],
"success": false
}
身份验证来保护我的某些路由,并按如下所示应用了Passport JWT
:
app / middlewares / authMiddleware.js
authMiddleware
app / routes / approutes.js
const express = require('express');
const router = express.Router();
const passport = require('passport');
const _ = require('lodash');
router.all('*', function (req, res, next) {
passport.authenticate('local', function(err, user, info) {
// If authentication failed, `user` will be set to false. If an exception occurred, `err` will be set.
if (err || !user || _.isEmpty(user)) {
// PASS THE ERROR OBJECT TO THE NEXT ROUTE i.e THE APP'S COMMON ERROR HANDLING MIDDLEWARE
return next(info);
} else {
return next();
}
})(req, res, next);
});
module.exports = router;
答案 5 :(得分:0)
一个简短的解决方法是模拟最初旨在支持connect-flash的Flash方法调用,并使用此方法返回JSON对象。
首先定义“仿真器”:
var emulateFlash = function (req, res, next) {
req.flash = (type, message) => {
return res.status(403).send({ status: "fail", message });
}
next();
}
这将注入flash方法,该方法将在失败时发送错误的JSON对象。
在路线中执行以下操作:
首先,使用以下命令全面使用仿真器:
router.use(emulateFlash);
相反,可以在所需的每条路由上使用emulateFlash方法。
2,在使用身份验证的路由上,使用以下消息指定failFlash选项:
router.route("/signin")
.post(.authenticate('local', { session: false, failureFlash: "Invalid email or password."}), UsersController.signIn);
我对身份验证失败和成功都进行了测试,发现它可以正常工作。查看代码,除了实现需要更多工作的回调方法外,我找不到其他任何方法来返回对象。