2012-06-30 4 views
26

J'ai une configuration Passport pour authentifier les utilisateurs stockés dans mongodb. Semble fonctionner correctement: l'authentification réussit/échoue de manière appropriée et les variables de session sont définies. Cependant, obtenir Passport pour vérifier une session échoue. Quelque chose semble être tout à fait faux dans le fait que les instructions console.log que j'ai ajoutées au rappel deserializeUser ne voient jamais la lumière du jour. Je suppose que mon problème est lié à deserializeUser jamais appelé. Quelqu'un est-il capable de diagnostiquer mon faux pas?PassportJS deserializeUser n'a jamais été appelé

// Passport configuration 
passport.serializeUser(function(user, cb){ cb(null, user.id) }); 
passport.deserializeUser(function(uid, cb){ 
    console.log("Trying to deserialize user: "+uid); 
    User.findById(uid, function(err, user){ 
    cb(err, user); 
    }); 
}); 
// auth strategy function 
passport.use(new LocalStrategy({usernameField: 'email'}, 
    function(email, pass, done){ 
    User.findOne({email: email}, function (err, user) { 
     if (err) 
     return done(err); 
     if (!user) 
     return done(null, false, {message: "Couldn't find user"}); 
     var crypted = bcrypt.hashSync(pass, user.salt); 
     if(user.hashpass != crypted) 
     return done(null, false, {message: "Bad password"}); 
     return done(null, user); 
    }); 
    } 
)); 

passport.CreateSession = function (req, res, next) { 
    passport.authenticate('local', function(err, user, info){ 
    if(err || !user) 
     return res.json({status: "Failure: "+err}); 
    req.logIn(user, function (err){ 
     if(err) 
     return res.json({status: "Failure: "+err}); 
     return res.json({status: "Authenticated"}); 
    }); 
    })(req, res, next); 
}; 

avec ce qui suit dans app.js:

app.post('/session', passport.CreateSession); // restify better 
app.del('/session', passport.DestroySession); 
app.get('/images', passport.CheckSession, routes.images); 

Répondre

9

Avez-vous use() « d passport.session() middleware? Comme dans cet exemple:

https://github.com/jaredhanson/passport-local/blob/v1.0.0/examples/login/app.js#L91

C'est ce qui restaure la session et appelle deserializeUser, il sonne comme ça peut manquer.

+0

Jared - merci pour votre aide. Oui, j'ai app.use (passport.session()); dans app.js –

+0

Ceci est le noeud 0.8.0, expresse 2.5.10, et le dernier passeport, btw. –

+0

Hmm, et je suppose que vous avez vos sessions correctement configurées et persistées aussi?Si oui, je ne vois rien d'évident. Voici ma suggestion: 1. Essayez d'exécuter sous le noeud 0.6.x, pour voir s'il y a une incompatibilité quelque part avec 0.8. 2. Poster un runnable, copie-n-coller l'essentiel, et je vais le courir et voir ce que je peux trouver. –

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

passport.deserializeUser(
    function(id, done){ 
     User.findById(id, function(err, user){ 
      if(err){ 
       done(err); 
      } 
      done(null, user); 
     }); 
}); 

**> try this one** 
21

Pour quelqu'un d'autre qui est d'avoir ce problème, jetez un oeil à ceci:

app.use(session({ 
    secret: 'something', 
    cookie: { 
     secure: true 
    }})); 

Si vous avez cookie.secure ensemble true et que vous n'êtes pas en utilisant le protocole SSL (protocole https par exemple), la cookie avec l'identifiant de session n'est pas retourné au navigateur et tout échoue silencieusement. Retrait de ce drapeau a résolu le problème pour moi - il a fallu des heures pour le réaliser!

+3

Dave, est la session ici "express-session"? Pouvez-vous faire cela clair –

+1

Cela devrait être la bonne réponse –

+0

Ce fut le problème pour moi, et il a fallu 2 jours de travail pour trouver cette réponse ... Merci! –

1

J'ai combattu le même problème toute la journée. J'ai eu un rappel personnalisé mis en place pour faire des autorisations (comme au bas de http://passportjs.org/guide/authenticate/). Il semble que Passport prétraite tous les objets de requête avant même qu'ils ne touchent l'autre middleware (en fonction de certaines instructions de journalisation que j'ai écrites). Dans le cadre de ce prétraitement, il place les informations utilisateur désérialisées dans l'objet request.user. Malheureusement, le comportement par défaut de passport.authenticate ('local', callback) semble être d'ignorer les données de session ou de cookie et de supposer que le nom d'utilisateur et le mot de passe sont envoyés dans l'objet de requête. Ce que j'ai fait pour corriger cela était de vérifier d'abord l'objet request.user, et s'il existait, cela signifiait que Passport avait fait son prétraitement et que je pouvais ensuite appeler directement la connexion. Voici ma fonction d'autorisation, que je l'utilise à la place de passport.authenticate (« local »):

function doAuth(request, response, next) 
{ 

if (request.user) { 
    request.logIn(request.user, function (err) { 
     if (err) { 
      console.log(err); 
      response.status(500).json({message: 
        "Login failed. Auth worked. Nonsense"}); 
      return; 
     } 
     console.log("doAuth: Everything worked."); 
     next(); 
    }); 
    return; 
} 

passport.authenticate('local', function(err, user, info) { 
    if (err) { 
     response.status(500).json({message: "Boo Passport!"}); 
     return; //go no further 
     //until I figure out what errors can get thrown 
    } 
     console.log("Authentication failed. Here is my error:"); 
     console.log(err); 
     console.log("Here is my info:"); 
     console.log(info); 
     response.status(500).json({message: "Authentication failed."}); 
     return; 
    } 
    request.logIn(user, function(err) { 
     if (err) { 
     console.log("Login failed. This is the error message:"); 
     console.log(err); 
     response.status(500).json({message:"Login failed."}); 
      return; 
     } 
     console.log("doAuth: Everything worked. I don't believe it."); 

     next(); 
    }); 
})(request, response, next); 

} 
+0

Votre explication m'a beaucoup aidé, je n'ai pas appliqué votre solution, mais vous avez signalé le problème: D –

14

Si vous utilisez le rappel authenticate lorsque vous authentifiez avec passeport, vous devez connecter l'utilisateur manuellement. Ça ne sera pas appelé pour toi.

passport.authenticate('local', function (err, user) { 
    req.logIn(user, function (err) { // <-- Log user in 
     return res.redirect('/'); 
    }); 
})(req, res); 
+0

Des documents du passeport: 'Note: passport.au Le middleware thenticate() appelle automatiquement req.login(). Cette fonction est principalement utilisée lorsque les utilisateurs s'inscrivent, au cours de laquelle req.login() peut être invoqué pour se connecter automatiquement à l'utilisateur nouvellement enregistré. » – jbodily

+2

Vous pouvez revérifier que si vous faites une authentification manuellement, elle ne sera pas appelée. – Rick

+2

La réponse de Rick est correcte. J'ai passé des heures à le comprendre ... – BlackSoil

-1

assurez-vous que la ligne de code app.use(express.static(path.join(__dirname, 'public'))); reste inférieur aux app.use(require('express-session')

+0

Pourquoi? Cet ordre n'a pas d'importance pour le problème -' deserializeUser' n'est pas appelé non plus.Vous obtenez également une requête DB sur la requête EVERY assets.Etes-vous sûr de devoir interroger la session pour chacun de vos 'styles.css'? – Green

0

Aujourd'hui, je fait face à la même question, et dans mon cas, la cause est ainsi du côté client fait les appels API. Et l'approche suivante m'a aidé à surmonter le problème:

const doFetch(url, method = 'GET', body) { 
    const headers = new Headers(); 
    headers.append('Content-Type', 'application/json'); 
    headers.append('Accept', 'application/json'); 
    headers.append('Cache', 'no-cache'); 
    const params = { 
    method, headers, 
    credentials: 'include' // The cookie must be sent! 
    } 
    if(body) { 
    params.body = body; 
    } 
    return fetch(url, params); 
} 

Après cela, deserializeUser a commencé à être appelé correctement.