【问题标题】:Nodejs and PassportJs: Redirect middleware after passport.authenticate not being called if authentication failsNodejs和PassportJs:如果身份验证失败,则不会调用passport.authenticate后重定向中间件
【发布时间】:2014-05-16 12:36:13
【问题描述】:

我没有登录页面,而是在每个页面上都有一个登录表单。无论身份验证是否成功(使用适当的闪存消息),我都想将用户重定向回他们所在的同一页面

取以下代码:

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);
});

如果通过了身份验证,我只会看到上面的最终中间件被调用。如果失败,则护照似乎以获取请求的形式将我重定向到 /login。在我的应用中,此页面不存在。

如果我在护照身份验证函数中传递一个额外的选项对象作为参数,那么这可以工作:

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

}


));

但是这样做我失去了选择将用户重定向到哪里的能力。如果身份验证失败,护照似乎可以控制用户被重定向到的位置。我怎样才能解决这个问题?或者它是一个错误?如果身份验证失败,护照身份验证必须是链中的最后一个中间件吗?

这是我的本地策略函数调用:

//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);
    });

}));

【问题讨论】:

    标签: node.js passport.js


    【解决方案1】:

    我知道对于像我这样尝试了所有建议选项但没有成功的人来说,这可能仍然是个问题。

    就我而言,事实证明,我收到了错误,因为我的 req.body 对象始终为空。我的 body 解析中间件设置正确,所以为什么会发生这种情况没有意义。

    经过更多研究,我发现 body-parser 不支持我用于表单(multipart/form-data)的 enctype - 请参阅他们的 read me - 在切换到不同的中间件、multer 后,一切工作顺利。

    【讨论】:

      【解决方案2】:

      我遇到了与成功的 Facebook Auth 之后重定向调用相同的问题

      • passport.authenticate('facebook', ..)

      ..没有受到尊重。

      基于“本地”passportJS 策略 - 以及来自 @ploutch's answer here 的一个很好的提醒。我意识到让它工作的关键似乎在这个电话中:

      req.logIn(user, function(err) {
       ...
      }
      

      对于 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');
                  });      
              }
      ); 
      

      【讨论】:

      • 这个我看不懂。如果 passport.authenticate('facebook') 中间件成功完成并且你的下一个匿名函数被调用(这是它可以被调用的唯一方法),那么你已经登录并且 req.login() 调用是多余的。
      • @TimHardy 我发现这种类型的结构非常棘手/困惑自己;我根本不喜欢复杂的身份验证结构.. grumble,grumble。对于这里的解决方案 - 符合条件的关键词是 “这条路线设置对我有用” :)
      【解决方案3】:

      完整答案,包括:

      • 设置redirectUrl的中间件
      • 快讯
      • 不返回不会被使用的值

      只需在您的 loginRequired 中间件中创建一个 redirectTo 值:

      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')
      }
      

      然后在您的登录 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);
      });
      

      【讨论】:

      • 据我所知,您调用 next 并没有成功,这通常是使用护照中间件登录用户的方式。您正在调用 req.login,它手动将用户登录,并且您正在实施自定义重定向。
      • 是的,蒂姆这是一个准确的描述。也许.next() 更惯用?你怎么看?只要代码有效,欢迎您编辑帖子!
      【解决方案4】:

      您可以使用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);
      });
      

      【讨论】:

      • 为您辩护,它是一个相当简洁的大型概念手册。 (我自己也遇到过类似的问题……)
      • 我们是否需要为此添加“本地策略”?就我而言,它给了我未知本地策略的错误。
      猜你喜欢
      • 2021-09-11
      • 2018-05-11
      • 2016-06-28
      • 1970-01-01
      • 2016-04-03
      • 1970-01-01
      • 2011-07-24
      • 2018-07-02
      • 1970-01-01
      相关资源
      最近更新 更多