web-dev-qa-db-fra.com

Vérification des rôles et de l'authentification avec Passport.js

Je voudrais donc faire quelques itinéraires dans une API qui affichera différentes données en fonction du rôle d'utilisateur, défini dans MongoDB. Voici un échantillon de ce que j'ai en ce moment, cela fonctionne ...

router.get('/test', passport.authenticate('bearer', {session: false}), function (req, res) {
    if (req.user.role == "premium") {
        return res.send('you can see this content');
    }
    else {
        return res.send('you can not see this content');
    }
})

Cependant, l'objectif final est de présenter au moins quelque chose à l'utilisateur, même s'il n'est pas connecté ou authentifié avec le bon type de rôle.

router.get('/test', passport.authenticate('bearer', {session: false}), function (req, res) {
    if (req.user.role == "premium") {
        return res.send('this is premium content');
    }
    else {
        // could be hit by another role, or no user at all
        return res.send([some truncated version of the premium content]);
    }
})

Ce que je pense que je trouverais comment travailler, mais je ne sais pas comment spécifier le même itinéraire qui pourrait éventuellement être atteint sans aucun en-tête d'autorisation dans la demande.

Est-ce possible dans Passport.js/Express?

15
user393219

Je suggère que vous utilisiez des codes d'état HTTP et un objet d'erreur, il s'agit d'une convention API commune et elle permet à vos utilisateurs d'API de savoir ce qui se passe et pourquoi:

app.get('/premium-resource', function(req, res, next) {
  passport.authenticate('bearer', function(err, user) {
    if (user){
      if (user.role === 'premium'){
        return res.send(200,{userContent:'you are a premium user'});
      }else{
        return res.send(403,{
          'status': 403,
          'code': 1, // custom code that makes sense for your application
          'message': 'You are not a premium user',
          'moreInfo': 'https://myawesomeapi.io/upgrade'
        });
      }
    }else{
      return res.send(401,{
        'status': 401,
        'code': 2, // custom code that makes sense for your application
        'message': 'You are not authenticated.',
        'moreInfo': 'https://myawesomeapi.io/docs'
      });
    }
  })(req, res, next);
});

Avertissement: je travaille chez Stormpath et nous avons beaucoup réfléchi à l'authentification et à la conception d'API, nous avons vraiment une présentation sur le sujet:

https://stormpath.com/blog/designing-rest-json-apis/

9
robertjd

La solution consiste à limiter le contenu de la vue plutôt que l'itinéraire.

router.get('/test', authenticationMiddleware, function(req, res){
    var premiumFlag = req.user.role;
    res.send('premiumontent', {role: premiumFlag});
});

premiumContent.jade

p This content is visible to all users

- if role === "premium"
    p this content is only visible to premium users
7
takinola

La solution que j'ai trouvée à ma réponse est d'utiliser une adaptation de la documentation Passportjs.org .

Dans les itinéraires dont j'ai besoin pour renvoyer des données, qu'un utilisateur soit connecté ou non, je peux utiliser quelque chose comme:

// Test to check for authentication
app.get('/login', function(req, res, next) {
  passport.authenticate('bearer', function(err, user, info) {
    if (user)
        // check user's role for premium or not
        if (user.role == "premium")
            return res.send('user is premium')
        else
            return res.send('user is not premium');
    else
        // return items even if no authentication is present, instead of 401 response
            return res.send('not logged in');
  })(req, res, next);
});
1
user393219