2014-04-04 15 views
12

Non ho una pagina di accesso, ma ho un modulo di accesso che appare su ogni pagina. Voglio riorientare utente alla stessa pagina che erano sulla indipendentemente dal fatto che l'autenticazione ha avuto successo (con opportuni messaggi flash)Nodejs e PassportJs: reindirizza il middleware dopo che passport.authenticate non viene chiamato se l'autenticazione fallisce

Prendere il seguente codice:

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

vedo solo il middleware finale sopra essere chiamato se l'autenticazione è passata. Se fallisce, sembra che il passaporto mi stia reindirizzando a/login sotto forma di richiesta get. Nella mia app questa pagina non esiste.

Se mi passa un ulteriore opzioni oggetto come un parametro nella funzione passaporto autenticazione allora questo funziona:

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 

} 


)); 

Ma nel fare questo ho perdere la capacità di scegliere dove reindirizzare l'utente a. Sembra che il passaporto abbia il controllo su dove viene reindirizzato l'utente se l'autenticazione fallisce. Come posso risolvere questo? o è un bug? Il passaporto deve autenticare l'ultimo middleware della catena se l'autenticazione fallisce?

Questo è il mio locale chiamata di funzione strategia:

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

})); 

risposta

25

è possibile utilizzare un callback autenticazione personalizzata come descritto nell'ultimo paragrafo lì 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

Questo funziona. Grazie. (Nota per auto ... leggi sempre il manuale). – Paulie

+5

In tua difesa, è un manuale piuttosto conciso per un concetto grande. (incontrando problemi simili io stesso ...) –

+0

Abbiamo bisogno di includere "strategia locale" per questo? Nel mio caso mi sta dando errore di strategia locale sconosciuta. – adi

3

stavo correndo lo stesso problema in cui il redirect-chiamate, che seguono il successo di Facebook Auth

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

.. non sono stati onorati.

Basato sulla strategia di passportJS "locale" - e un bel promemoria di quello da @ploutch's answer here ..Ho capito la chiave per ottenere al lavoro sembra essere in questa chiamata:

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

Per Facebook, questa configurazione percorso ha lavorato per me:

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

Questo non capisco. Se il middleware passport.authenticate ('facebook') è terminato correttamente e viene chiamata la tua prossima funzione anonima (questo è l'unico modo in cui è possibile ottenere il richiamo), sarà già connesso e la chiamata req.login() è ridondante. –

+0

@TimHardy Ho trovato questo tipo di struttura molto complicato/confondendo me stesso; non sono affatto un fan dei costrutti di autenticazione contorti .. * brontolare, brontolare *. Per la soluzione qui - le parole chiave qualificanti sono * "questa impostazione del percorso ha funzionato per me" * :) – gnB

0

risposta completa, tra cui:

  • Middleware per impostare redirectUrl
  • Messaggi flash
  • Non restituire valori che non saranno sed

Basta creare un valore di redirectTo nella vostra loginRequired middleware:

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

E poi nel tuo post login:

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

Solo così ho capito, non si sta chiamando con successo, che è ciò che normalmente registra l'utente con il middleware del passaporto. Stai invece chiamando req.login, che registra manualmente l'utente e stai implementando un reindirizzamento personalizzato. –

+0

Sì, Tim è una descrizione accurata. Forse '.next()' è più idiomatico? Cosa ne pensi? Sei libero di modificare il post finché il codice funziona! – mikemaccana

Problemi correlati