Nodejs和PassportJs:如果身份验证失败,则在passport.authenticate之后重定向中间件不被调用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22858699/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Nodejs and PassportJs: Redirect middleware after passport.authenticate not being called if authentication fails
提问by Paulie
I have no login page but rather I have a login form that appears on every page. I want to redirect user back to the same page they were on regardless of whether authentication was successful (with appropriate flash messages)
我没有登录页面,而是在每个页面上都有一个登录表单。我想将用户重定向回他们所在的同一页面,无论身份验证是否成功(使用适当的 flash 消息)
Take the following code:
取以下代码:
app.post('/login', validateLogin, passport.authenticate('local-login'), function(req, res) {
var redirectUrl = '/';
if(req.body.to.length > 0){
redirectUrl = req.body.to;
}
console.log("THIS IS ONLY CALLED IF passport.authenticate() IS SUCCESSFUL");
res.redirect(redirectUrl);
});
I only see the final middleware above being called if authentication is passed. If it fails then passport appears to be redirecting me to /login in the form of a get request. In my app this page doesn't exist.
如果通过身份验证,我只会看到上面的最终中间件被调用。如果失败,那么passport 似乎以get 请求的形式将我重定向到/login。在我的应用程序中,此页面不存在。
If I pass an additional options object as a parameter in the passport authenticate function then this works:
如果我在通行证身份验证函数中传递一个额外的选项对象作为参数,那么这有效:
app.post('/login', validateLogin, passport.authenticate('local-login', {
successRedirect : '/', // redirect to the secure profile section
failureRedirect : '/signup', // redirect back to the signup page. THIS IS JUST FOR TESTING TO SEE IF THE REDIRECT ON FAIL WORKS.
failureFlash : true, // allow flash messages
}
));
But in doing this I lose the ability to choose where to redirect the user to. It seems that passport takes control over where the user is redirected to if authentication fails. How can I fix this? Or is it a bug? Must passport authenticate be the last middleware in the chain if authentication fails?
但是这样做我失去了选择将用户重定向到哪里的能力。如果身份验证失败,护照似乎可以控制用户重定向到的位置。我怎样才能解决这个问题?或者这是一个错误?如果身份验证失败,护照身份验证必须是链中的最后一个中间件吗?
This is my local strategy function call:
这是我的本地策略函数调用:
//LOCAL LOGIN
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) { // callback with email and password from our form
console.log("IN PASSPORT");
if(email.length == 0 || password.length == 0){
console.log("FIELDS ARE EMPTY");
return done(null, false, req.flash('loginMessage', 'Fill in all values.'));
}
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({ 'local.email' : email }, function(err, user) {
// if there are any errors, return the error before anything else
if (err){
return done(err);
console.log("db err");
}
// if no user is found, return the message
if (!user){
console.log("not user");
return done(null, false, req.flash('loginMessage', 'Incorrect details.')); // req.flash is the way to set flashdata using connect-flash
}
// if the user is found but the password is wrong
if (!user.validPassword(password)){
console.log("invalid pw");
return done(null, false, req.flash('loginMessage', 'Incorrect details.')); // create the loginMessage and save it to session as flashdata
}
// all is well, return successful user
console.log("All OK");
return done(null, user);
});
}));
回答by ploutch
You could use a custom authentication callback as described in the last paragraph there http://passportjs.org/guide/authenticate/.
您可以使用http://passportjs.org/guide/authenticate/上一段中所述的自定义身份验证回调。
app.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
// Redirect if it fails
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
// Redirect if it succeeds
return res.redirect('/users/' + user.username);
});
})(req, res, next);
});
回答by Gene Bo
I was running into the same issue where the redirect-calls , that follow successful Facebook Auth
我遇到了同样的问题,即在成功的 Facebook Auth 之后重定向调用
- passport.authenticate('facebook', ..)
- passport.authenticate('facebook', ..)
.. were not being honored.
..没有受到尊重。
Based on 'local' passportJS Strategy - and a nice reminder of that from @ploutch's answer here.. I realized the key to getting it to work seems to be in this call:
基于“本地”passportJS 策略 - 并从@ploutch 的回答中很好地提醒了这一点......我意识到让它工作的关键似乎在这个电话中:
req.logIn(user, function(err) {
...
}
For Facebook, this route setup worked for me:
对于 Facebook,此路线设置对我有用:
app.get(
'/auth/facebook/callback',
passport.authenticate
(
'facebook',
{ failureRedirect: '/fbFailed' }
),
function(req, res)
{
var user = myGetUserFunc(); // Get user object from DB or etc
req.logIn(user, function(err) {
if (err) {
req.flash('error', 'SOMETHING BAD HAPPEND');
return res.redirect('/login');
}
req.session.user = user;
// Redirect if it succeeds
req.flash('success', 'Fb Auth successful');
return res.redirect('/user/home');
});
}
);
回答by mikemaccana
Full answer, including:
完整答案,包括:
- Middleware to set redirectUrl
- Flash messages
- Not returning values that won't be used
- 设置redirectUrl的中间件
- 快讯
- 不返回不会被使用的值
Just create a redirectTovalue in your loginRequiredmiddleware:
只需redirectTo在您的loginRequired中间件中创建一个值:
var loginRequired = function(req, res, next) {
if ( req.isAuthenticated() ) {
next();
return
}
// Redirect here if logged in successfully
req.session.redirectTo = req.path;
res.redirect('/login')
}
And then in your login POST:
然后在您的登录 POST 中:
router.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if ( err ) {
next(err);
return
}
// User does not exist
if ( ! user ) {
req.flash('error', 'Invalid email or password');
res.redirect('/login');
return
}
req.logIn(user, function(err) {
// Invalid password
if ( err ) {
req.flash('error', 'Invalid email or password');
next(err);
return
}
res.redirect(req.session.redirectTo || '/orders');
return
});
})(req, res, next);
});
回答by Morrey Davidson
I know this might still be a problem for some people like me who tried all the suggested options without any success.
我知道对于像我这样尝试了所有建议选项但没有成功的人来说,这可能仍然是一个问题。
In my case, as it turned out, I was getting the error because my req.body object was always empty. I had my body parsing middleware set up correctly so it didn't make sense why this was happening.
就我而言,事实证明,我收到错误消息是因为我的 req.body 对象始终为空。我的身体解析中间件设置正确,所以为什么会发生这种情况是没有意义的。
After more research I found out that the enctype I was using for my forms(multipart/form-data) isn't supported by body-parser - see their read me- after switching to a different middleware, multer, everything worked smoothly.
经过更多研究,我发现 body-parser 不支持我用于表单(multipart/form-data)的 enctype - 请参阅他们的自述- 在切换到不同的中间件后,multer,一切顺利。

