2014-04-04 49 views
12

我還沒有登錄頁面,而是我有每一頁上出現一個登錄表單passport.authenticate不會被調用後重定向中間件。我想重定向用戶返回到同一頁面,他們就不管的認證是否成功(在適當的提示信息)和的NodeJS PassportJs:如果驗證失敗

看看下面的代碼:

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

我只看到上面被稱爲最後的中間件如果認證通過。如果它失敗了,那麼護照似乎是以get請求的形式將我重定向到/ 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); 
    }); 

})); 

回答

25

在最後一段有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); 
}); 
+0

這工作。謝謝。 (注意自己...總是閱讀手冊)。 – Paulie

+5

在你的防守中,這是一個相當簡潔的大型概念手冊。 (自己遇到類似的問題......) –

+0

我們是否需要爲此包含「本地策略」?在我的情況下,它給我錯誤的未知本地策略。 – adi

3

我也陷入了同樣的問題,即重定向通話,隨後Facebook的成功驗證

  • 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'); 
      });  
     } 
); 
+0

這一個我不明白。如果passport.authenticate('facebook')中間件成功完成,並且您的下一個匿名函數被調用(這是它可以被調用的唯一方式),那麼您已經登錄並且req.login()調用是多餘的。 –

+0

@TimHardy我發現這種類型的結構非常棘手/混淆我自己;我根本不是一個瘋狂的認證結構迷。*抱怨,抱怨*。對於這裏的解決方案 - 合格的關鍵詞是*「這個路線設置爲我工作」* :) – gnB

0

完整的答案,包括:

  • 中間件設置redirectUrl
  • Flash消息
  • 不返回不會返回的值SED

就在您的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); 
}); 
+0

就這樣,我明白,你不會與成功,然後通話記錄用通行證護照中間件。您改爲調用req.login,它手動記錄用戶,並且您正在實施自定義重定向。 –

+0

是的蒂姆這是一個準確的描述。也許'.next()'更具慣用性?你怎麼看?只要代碼正常工作,歡迎您編輯帖子! – mikemaccana