web-dev-qa-db-fra.com

Login Passport et session persistante

Contexte

J'ai une application MEAN avec des fonctionnalités CRUD entièrement testée avec postman. J'essaie de continuer à me connecter depuis un certain temps, sans succès. J'ai lu et essayé ce qui suit 

Mais j’ai seulement été capable d’enregistrer et de connecter un utilisateur, et non de rester connecté avec une session.

Mon application

Ici est un lien vers le dépôt complet de github (si vous recherchez les dernières modifications, vérifiez développer une branche)

Ma compréhension de l'authentification/connexion

Voici ma compréhension de la connexion de l'utilisateur avec des exemples de code de mon projet et une capture d'écran des résultats du facteur ainsi que les journaux de la console.

Configuration du passeport

J'ai le fichier auth.js suivant, il configure le passeport

var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;

module.exports = function(app, user){

  app.use(passport.initialize());
  app.use(passport.session());

  // passport config
  passport.use(new LocalStrategy(user.authenticate()));

  passport.serializeUser(function(user, done) {
    console.log('serializing user: ');
    console.log(user);
    done(null, user._id);
  });

  passport.deserializeUser(function(id, done) {
    user.findById(id, function(err, user) {
      console.log('no im not serial');
      done(err, user);
    });
  });
};

Ceci est appelé dans le fichier serveur comme

//code before
var user    = require('./models/user.js');
var auth    = require('./modules/auth.js')(app, user);
// code after

Routage pour la connexion

Dans mes itinéraires, j'ai l'itinéraire de connexion comme suit

router.post('/login', function(req, res, next) {

  passport.authenticate('local', function(err, user, info) {

    if (err) {
        return next(err);
    }

    if (!user) {
        return res.status(401).json({
            err: info
        });
    }

    req.logIn(user, function(err) {

        if (err) {
            return res.status(500).json({
                err: 'Could not log in user'
            });
        }

        res.status(200).json({
            status: 'Login successful!'
        });

    });
  })(req, res, next);
});

Cette route fonctionne telle que testée avec le facteur. J'entre les détails 'joe' et 'pass' et j'obtiens la réponse suivante.

 enter image description here

Lorsque cette route est atteinte, nous pouvons également voir dans la console que l’utilisateur est sérialisé.

 enter image description here

Quoi ensuite?

C'est là que je me perds. J'ai quelques questions.

  1. L'utilisateur est-il maintenant en session sur mon serveur?
  2. Dois-je renvoyer le req.session.passport.user au client?
  3. Ai-je besoin de l'ID de session pour toutes les demandes futures?

Tester la session

J'ai une deuxième configuration de route pour tester la session:

router.get('/checkauth', passport.authenticate('local'), function(req, res){

    res.status(200).json({
        status: 'Login successful!'
    });

});

La partie passport.authenticate('local') (je pensais) est là pour tester si la session utilisateur existe avant de donner accès à la route, mais je ne reçois jamais de réponse 200 lorsque je lance ceci, même après une connexion.

Est-ce que cette route attend un req.session.passport.user passé en tête ou un argument de données sur une requête http nécessitant une autorisation?

Si quelque chose me manque ou si je comprends quelque chose qui ne va pas, dites-le-moi, toute contribution est la bienvenue. Merci a tous.

27
Joe Lloyd

L'utilisateur est-il maintenant en session sur mon serveur?

Non, vous devez utiliser le middleware express-session avant app.use(passport.session()); pour stocker la session dans la mémoire/la base de données. Ce middleware est responsable de la configuration des cookies pour les navigateurs et convertit les cookies envoyés par les navigateurs en un objet req.session. PassportJS utilise uniquement cet objet pour désérialiser davantage l'utilisateur.

Devrais-je envoyer le req.session.passport.user au client?

Si votre client attend une ressource user lors de la connexion, vous devriez le faire. Sinon, je ne vois aucune raison d'envoyer l'objet utilisateur au client.

Ai-je besoin de l'identifiant de session pour toutes les futures demandes?

Oui, pour toutes les futures demandes, l'identifiant de session est requis. Mais si votre client est un navigateur, vous n'avez rien à envoyer. Le navigateur stockera l'identifiant de session en tant que cookie et l'enverra pour toutes les demandes ultérieures jusqu'à l'expiration du cookie. express-session lira ce cookie et joindra l'objet de session correspondant sous la forme req.session.

Tester la session

passport.authenticate('local') sert à authentifier les informations d'identification de l'utilisateur à partir du corps POST. Vous devriez utiliser ceci uniquement pour la route de connexion.

Mais pour vérifier si l'utilisateur est authentifié sur toutes les autres routes, vous pouvez vérifier si req.user est défini.

function isAuthenticated = function(req,res,next){
   if(req.user)
      return next();
   else
      return res.status(401).json({
        error: 'User not authenticated'
      })

}
router.get('/checkauth', isAuthenticated, function(req, res){

    res.status(200).json({
        status: 'Login successful!'
    });
});
49
hassansin

Comme @hassansin dit que vous devez utiliser un middleware qui implémente la gestion de session. Le middleware passport.session () consiste à connecter la structure de passeport à la gestion de session et à ne pas implémenter la session elle-même. Vous pouvez utiliser le middleware express-session pour implémenter la gestion de session. Vous devez modifier votre auth.js de la manière suivante

var passport = require('passport');
var session = require('express-session');
var LocalStrategy = require('passport-local').Strategy;

module.exports = function(app, user){
  app.use(session({secret: 'some secret value, changeme'}));    

  app.use(passport.initialize());
  app.use(passport.session());

  // passport config
  passport.use(new LocalStrategy(user.authenticate()));

  passport.serializeUser(function(user, done) {
    console.log('serializing user: ');
    console.log(user);
    done(null, user._id);
  });

  passport.deserializeUser(function(id, done) {
    user.findById(id, function(err, user) {
      console.log('no im not serial');
      done(err, user);
    });
  });
};

Notez que dans ce cas, le moteur de session utilise le magasin en mémoire et ne fonctionne pas si vous redimensionnez votre application et appliquez un équilibrage de charge. Lorsque vous atteignez cet état de développement, il vous faudra quelque chose comme le connect-redis session store .

Notez également que vous devez modifier la valeur secrète utilisée lors de l'appel du midleware de session et utiliser la même valeur sur toutes les instances d'application.

9
yeiniel

Conformément à la documentation passport , req.user sera défini sur l'utilisateur authentifié. Pour que cela fonctionne, vous aurez besoin du module express-session. Vous ne devriez avoir besoin de rien d'autre que ce que vous avez déjà pour que votre passeport fonctionne.

En ce qui concerne le test de la session, vous pouvez avoir une fonction middleware qui vérifie si req.user est défini. Si c'est le cas, nous savons que l'utilisateur est authentifié et si ce n'est pas le cas, vous pouvez le rediriger.

Vous pouvez par exemple avoir une fonction de middleware que vous pouvez utiliser sur toutes les routes que vous souhaitez authentifier.

authentifié.js

module.exports = function (req, res, next) {
    // if user is authenticated in the session, carry on
    if (req.user) {
        next();
    }
    // if they aren't redirect them to the login page
    else {
        res.redirect('/login');
    }
};

manette

var authenticated = require('./authenticated');

router.get('/protectedpage', authenticated, function(req, res, next) {
    //Do something here
});
1
Michael Hamilton