2013-02-22 26 views
15

Utilizzo Passport per l'autenticazione nella mia app e utilizzo anche Express. Per riassumere il mio problema: mia funzionalità di accesso funziona bene inizialmente, ma dopo tempi di sessione qualsiasi dell'utente fuori, non gli utenti sono in grado di accedereScadenza cookie node.js Express Passport

Sto usando la strategia locale standard per l'autenticazione..

io includo come nudo esempio possibile in base alla mia messa a punto:

//------------- 
//Set up authentication with Passport 
//------------- 
var userModel = require('./models/user')(db); 
passport.use(new LocalStrategy(
    function(username, password, done) { 
     var errorMessage = 'Incorrect username/password combination.'; 
     userModel.GetUserByUsername(username, function(err, user) { 
      if (err) { return done(err); } 
      if (!user) { 
       return done(null, false, { message: errorMessage }); 
      } 

      user.validatePassword(password, function(isPasswordCorrect) { 
       if (!isPasswordCorrect) 
       { 
        return done(null, false, { message: errorMessage }); 
       } 

       //Update with login date 
       userModel.UpdateUserWithLogin(username, user.currentLoginTime, function(err){ 
        //if we have an error here, we should probably just log it 
        if(err) 
        { 
         console.log(err); 
        } 
       }); 

       return done(null, user); 
      }); 
     }); 
    } 
)); 

passport.serializeUser(function(user, done) { 
    done(null, user); 
}); 

passport.deserializeUser(function(user, done) { 
    userModel.GetUserByUsername(user._id, function(err, user) { 
      done(err, user); 
     }); 
}); 

//------------- 
//Set up express and configure 
//------------- 
var sessionStore = new SkinStore(db); 
var app = express(); 

app.configure(function(){ 
    app.set('port', process.env.PORT || 3000); 
    app.set('views', __dirname + '/views'); 
    app.engine('html', consolidate.swig); 
    app.set('view engine', 'html'); 
    swig.init({ 
     root: '.', 
     allowErrors: true, // allows errors to be thrown and caught by express instead of suppressed 
     autoescape: false}); 

    app.use(express.logger('dev')); 

    app.use(express.bodyParser()); 
    app.use(express.methodOverride()); 
    app.use(express.cookieParser("[mysecrethere]")); 
    app.use(express.session({ store: sessionStore, 
          cookie: { expires : new Date(Date.now() + 3600000) } //1 Hour 
          })); 
    app.use(passport.initialize()); 
    app.use(passport.session()); 
    app.use(flash()); 
    app.use(expressValidator); 

    app.use(express.static(path.join(__dirname, 'public'))); 

    //Dynamic helpers 
    app.use(require('./helpers/DynamicHelpers')); 

    app.use(app.router); 
}); 

app.get('/login', routes.login); 
app.post('/login', passport.authenticate('local', {failureRedirect: '/login', 
               badRequestMessage: "Please enter username and password", 
               failureFlash: true }), 
               function(req, res) { 
                var targetUrl = req.session.pageAfterLogin; 
                delete req.session.pageAfterLogin; 
                res.redirect(targetUrl || '/account'); 
               }); 

app.get('/account', IsAuthenticated, routes.account.show); 

E la funzione di supporto IsAuthenticated:

function IsAuthenticated(req,res,next){ 
    if(req.isAuthenticated()) 
    { 
     next(); 
    } 
    else 
    { 
     //save the requested page and then redirected 
     req.session.pageAfterLogin = req.url; 
     req.flash("error", "You must be logged in first!"); 
     res.redirect('/login'); 
    } 
} 

Cosa posso trovare per il debug è che, dopo il successo l'autenticazione (e dopo un cookie è scaduto), mi ha colpito questa logica (dall'alto):

function(req, res) { 
    var targetUrl = req.session.pageAfterLogin; 
    delete req.session.pageAfterLogin; 
    res.redirect(targetUrl || '/account'); 
} 

Dove posso vedere che il "req" ha la sessione impostata correttamente, con le informazioni sul passaporto memorizzate correttamente. Quindi, si verifica il reindirizzamento, la nuova richiesta non contiene informazioni sulla sessione e ha un ID sessione completamente nuovo. Sospettavo che non fosse stato impostato alcun cookie sul client, e sembra essere il caso, il che dovrebbe spiegare la mancanza di sessioni coerenti.

Tuttavia, non riesco a capire perché non è stato impostato alcun nuovo cookie per. C'è qualcosa di sbagliato nel modo in cui è configurata l'app che indicherebbe perché questo sta accadendo?

Devo aggiungere che il riavvio dell'istanza Node.js corregge il problema, non è qualcosa che sarebbe tollerabile in produzione.

Grazie.

UPDATE: Mi sono imbattuto Fiddler per vedere cosa stava succedendo con HTTP/S traffico, e posso vedere che quando funziona inizialmente, sto diventando un set di cookie nel browser (ho provato diversi), che è poi passato al server su richieste successive.

Quando il non funziona, il browser non trasmette cookie al server e pertanto Nodo invia un'intestazione Set-Cookie che fornisce ogni volta un nuovo cookie. Finora non ho avuto fortuna a determinare la causa di questo.

+0

Avete controllato che passport.deserializeUser viene eseguito, esiste quella user._id e che il modello trova l'utente? Anche serializeUser dovrebbe richiamare un id, non l'oggetto utente. –

+0

Sono riuscito a testarlo (finalmente), e posso vedere che serializeUser ** è ** chiamato. Tuttavia, nei successivi reindirizzamenti, deserializeUser non viene eseguito. In serializeUser, l'utente è stato trovato correttamente, ma non sembra persistere. E lavorerò per serializzare user._id al posto dell'utente. L'avevo fatto in origine, ma ho cambiato per qualche motivo che ho dimenticato. – creativename

risposta

24

L'ho capito, anche se non amo la risposta.

tl; dr; - usa maxAge anziché scade.


Il problema era radicato nella data di scadenza impostata su ciascun cookie (che viene impostato automaticamente da Express). Ho notato che ogni cookie impostato aveva la stessa data di scadenza, che alla fine si è ritrovata nel passato e quindi ha subito scadenza.

La causa di questo era qui:

cookie: { expires : new Date(Date.now() + 3600000) } 

La nuova data è stata essere creato solo una volta, al momento di avvio del server. Ciò faceva sì che la data di scadenza fosse la stessa ogni volta.In base al codice nel post originale, non riesco a capire perché non funziona eppure ogni esempio che ho trovato online utilizza lo stesso codice esatto. Ho verificato ciò definendo una funzione che ha creato questa data e controllando che sia stata richiamata solo all'avvio del server.

Per risolvere questo problema, sto definendo maxAge anziché "expires". maxAge richiede un numero di millisecondi, anziché una data, e sembra che imposti correttamente la data di scadenza su tutti i cookie.

Mi piacerebbe sapere se qualcuno può spiegare perché questo sta accadendo in primo luogo, dal momento che altri sembrano usarlo con successo. qualche idea?

Vedi il mio codice di lavoro al di sotto

app.configure(function(){ 
    app.set('port', process.env.PORT || 3000); 
    app.set('views', __dirname + '/views'); 
    app.engine('html', consolidate.swig); 
    app.set('view engine', 'html'); 
    swig.init({ 
     root: '.', 
     allowErrors: true, // allows errors to be thrown and caught by express instead of suppressed 
     autoescape: false}); 

    app.use(express.logger('dev')); 

    app.use(express.bodyParser()); 
    app.use(express.methodOverride()); 
    app.use(express.cookieParser("[mysecrethere]")); 
    app.use(express.session({ store: sessionStore, 
          cookie: { maxAge : 3600000 } //1 Hour 
          })); 
    app.use(passport.initialize()); 
    app.use(passport.session()); 
    app.use(flash()); 
    app.use(expressValidator); 

    app.use(express.static(path.join(__dirname, 'public'))); 

    //Dynamic helpers 
    app.use(require('./helpers/DynamicHelpers')); 

    app.use(app.router); 
}); 
+2

Grazie @creativename. Sono stato alle prese con questo problema per giorni. Dopo aver scoperto che il passaporto non ha aggiornato la proprietà di expires, ho pensato che sarebbe stato impossibile. Ma la tua soluzione funziona come un incantesimo! –

+1

grazie..questo è difficile da vedere. ha senso ora. – Timmerz

+1

Credo di trovarmi di fronte anche a questo problema, che riguarda gli utenti in un fuso orario dall'altra parte del mondo. –

-2

Set nome del cookie in valore, dove che può essere una stringa o un oggetto convertito in JSON. L'opzione del percorso è impostata su "/".

res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });

L'opzione MaxAge è un'opzione convenienza per l'impostazione "scade" relativo all'ora corrente in millisecondi. Quanto segue è equivalente all'esempio precedente.

res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })

anche il legame

http://expressjs.com/api.html#res.cookie

Problemi correlati