2 votes

Node express passeport (JWT) - rappel après authentification

J'ai l'authentification qui fonctionne avec passport JWT, mais j'ai du mal à exécuter une fonction de rappel/réponse, seulement si un utilisateur est authentifié. Comment cela peut-il être fait ?

Dans mes routes :

import express depuis 'express';
import passport depuis '../../config/passport';
import memberInfoCtrl depuis '../controllers/memberInfo';

const router = express.Router();

router.route('/membres')
  .get(membersCtrl.tokenCheck, passport.authenticate('jwt', { session: false }), membersCtrl.doSomethingElse);

export default router;

Je veux que membersCtrl.doSomethingElse soit exécuté si l'authentification est réussie.

Voici ma fonction tokenCheck :

function tokenCheck(req, res, next) {
  const token = getToken(req.headers);
  if (token) {
    const decoded = jwt.decode(token, config.secret);
    User.findOne({
      email: decoded.email
    }, (err, user) => {
      if (err) throw err;

      if (!user) {
        return res.status(403).send({
          success: false, msg: 'Authentification échouée. Utilisateur non trouvé.'
        });
      }
      // res.json({ success: true, msg: 'Bienvenue dans la zone réservée aux membres !' });
      return next();
    });
  } else {
    return res.status(403).send({ success: false, msg: 'Aucun jeton fourni.' });
  }
}

Utiliser res.json dans tokenCheck fonctionne bien, mais la fonction doSomethingElse n'est pas appelée par la suite.

Je pensais que c'était parce que nous renvoyer une réponse de cette manière :

res.json({ success: true, msg: 'Bienvenue dans la zone réservée aux membres !' });

Remplacer le res.json par return next(); renvoie l'erreur :

Erreur: Stratégie d'authentification inconnue "jwt"

Pourquoi cela se produit-il - comment puis-je vérifier l'authentification avant d'exécuter une autre fonction, pour la même route ?

Je suis sûr que c'est quelque chose de stupide que j'ai oublié. Toute aide est appréciée !

Voici une partie de mon script express principal qui initialise passport :

import passport depuis 'passport';
...
app.use(passport.initialize());

app.use('/api', routes);
...

Configuration de Passport :

const JwtStrategy = require('passport-jwt').Strategy;
import User depuis '../server/models/user';
import config depuis './env';

module.exports = (passport) => {
  const opts = {};
  opts.secretOrKey = config.secret;
  passport.use(new JwtStrategy(opts, (jwtPayload, done) => {
    User.findOne({ id: jwtPayload.id }, (err, user) => {
      if (err) {
        return done(err, false);
      }
      if (user) {
        done(null, user);
      } else {
        done(null, false);
      }
    });
  }));
};

3voto

Jonas Points 520

Votre approche générale est correcte. Pour protéger une route en fonction de certaines conditions, écrivez un middleware personnalisé appelant next() si ces conditions sont remplies.

Mais dans votre cas, ce n'est pas nécessaire car c'est ce que fait passport-jwt. Donc en supposant que vous avez configuré passport et passport-jwt correctement, tout ce que vous avez à écrire est ceci:

router.route('/membres')
    .get(passport.authenticate('jwt', { session: false }), membersCtrl.doSomethingElse);

passport-jwt extraira le JWT de la requête et le vérifiera avec votre clé secrète fournie. Ensuite, il utilisera le rappel verify de passport pour remplir req.user (source).

De plus: Oui, après avoir utilisé res.json(), une réponse est renvoyée, c'est pourquoi votre middleware passport et tout ce qui suit ne sera pas atteint dans ce cas.

Concernant votre erreur Erreur: Stratégie d'authentification inconnue \"jwt\": Cela se produit généralement si vous n'avez pas configuré correctement votre authentification par passport. Si vous l'incluez dans votre question, je l'examinerai et je compléterai ma réponse en conséquence.

Mise à jour: Votre code me semble bon sauf une chose: Vous n'avez pas spécifié l'attribut jwtFromRequest dans vos options de passport-jwt qui est obligatoire. Ou auriez-vous oublié d'invoquer votre configuration de passport par hasard?

Mise à jour 2: Clarification supplémentaire concernant mon commentaire ci-dessous:
1.) Importez votre module de configuration passport ES6 (où vous avez ajouté l'option jwtFromRequest) dans votre script principal express et invoquez-le:

import passport from 'passport';
import passportConfig from 'chemin/vers/passport/config';
...
app.use(passport.initialize());
passportConfig(passport);
...

2.) Assurez-vous de supprimer votre fonction tokenCheck, vous n'en avez pas besoin. Voir la première partie de cette réponse.

Mise à jour 3: 'Non autorisé' est parfait car cela signifie que vous protégez désormais avec succès votre route /membres. Pour mettre en place une authentification basée sur les jetons, vous avez maintenant besoin d'une autre route /authentifier où les utilisateurs peuvent demander l'accès à votre service web en fournissant des informations d'identification (votre route vérifiera ces informations et répondra avec un JWT qui doit être signé avec le même secret que celui que vous utilisez pour passport-jwt - sinon passport-jwt ne pourra pas vérifier la signature du jeton plus tard).

Mais cela dépasse le cadre de cette question. Il devrait y avoir de nombreuses ressources disponibles à ce sujet. Vous pouvez par exemple implémenter une route /authentifier en utilisant jsonwebtoken comme le montre cet article (ils n'utilisent pas du tout passport mais utilisent jsonwebtoken pour la création et la validation des jetons).

Remarque: Si vous implémentez également un client, vous devrez inclure une logique supplémentaire pour stocker le JWT et l'inclure dans vos requêtes à l'application express.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X