Création d'un middleware expressjs qui accepte les paramètres


105

J'essaye de créer un middleware qui peut accepter des paramètres. Comment cela peut-il être fait?

exemple

app.get('/hasToBeAdmin', HasRole('Admin'), function(req,res){

})

HasRole = function(role, req, res, next){
   if(role != user.role){
      res.redirect('/NotInRole);
   }

   next();
}

41
Ha, vous avez posé ma question exacte pour mon scénario exact, mais 6 ans plus tôt. SO est génial.
aero

6
@aero exactement la même chose que je recherchais: D
Jeson Dias

4
@aero 7 ans plus tard, je cherche exactement le même: D
jean d'arme

4
@aero 7+ ans plus tard, je cherche exactement la même chose!
sidd

4
@aero 8 ~ ans plus tard, je cherche exactement la même chose! \ o /
Ítalo Sousa

Réponses:


162
function HasRole(role) {
  return function(req, res, next) {
    if (role !== req.user.role) res.redirect(...);
    else next();
  }
}

Je veux également m'assurer de ne pas faire plusieurs copies de la même fonction:

function HasRole(role) {
  return HasRole[role] || (HasRole[role] = function(req, res, next) {
    if (role !== req.user.role) res.redirect(...);
    else next();
  })
}

9
La deuxième méthode met en cache les paramètres, qui peuvent ou non être le comportement souhaité.
Pier-Luc Gendreau

1
@Jonathan Ong, pouvez-vous expliquer la deuxième définition de la fonction. Que se passe-t-il là-bas? Je ne comprends pas la ligne suivante return HasRole [role] || (HasRole [role] = function (req, res, next) {
Rafay Hassan

1
@JonathanOng pourriez-vous s'il vous plaît expliquer un peu plus le deuxième exemple pour ceux qui ne connaissent pas si bien le nœud? (y compris moi). Quand pouvez-vous obtenir plusieurs copies de la même fonction et quand cela peut causer des problèmes? Merci.
Dave

sans mise en cache, app.get('/a', hasRole('admin'))et app.get('/b', hasRole('admin'))créerait une nouvelle fermeture pour chacun hasRole. cela n'a pas beaucoup d'importance de manière réaliste, sauf si vous avez une application vraiment volumineuse. je code juste comme ça par défaut.
Jonathan Ong

14
app.get('/hasToBeAdmin', (req, res, next) => {
  hasRole(req, res, next, 'admin');
}, (req,res) => { 
    // regular route 
});

const hasRole = (req, res, next, role) => {
   if(role != user.role){
      res.redirect('/NotInRole');
   }
   next();
};

Bonne et simple idée. L'intergiciel n'est vraiment qu'une fonction normale. Pourquoi ne pas lui transmettre d'autres valeurs. Veuillez inclure req, res et next dans la première fonction.
zevero

1
Bien que le code parle souvent de lui-même, il est bon d'ajouter des explications à votre code. Cela est apparu dans la file d'attente d'examen, car les réponses de code uniquement ont tendance à le faire.
Will le

Je pensais à cette approche avant de visiter SO, mais je me suis dit "Meh, il y a sûrement une meilleure façon". Après avoir visité, je constate que c'est vraiment le moyen le plus simple et le plus efficace.
Fusseldieb

3

Sinon, si vous n'avez pas trop de cas ou si le rôle n'est PAS une chaîne:

function HasRole(role) {
  return function (req, res, next) {
    if (role !== req.user.role) res.redirect(/* ... */);
    else next();
  }
}

var middlware_hasRoleAdmin = HasRole('admin'); // define router only once

app.get('/hasToBeAdmin', middlware_hasRoleAdmin, function (req, res) {

})

solution élégante
Leos Literak

2

Si vous avez différents niveaux d'autorisations, vous pouvez les structurer comme ceci:

const LEVELS = Object.freeze({
  basic: 1,
  pro: 2,
  admin: 3
});

/**
 *  Check if user has the required permission level
 */
module.exports = (role) => {
  return (req, res, next) => {
    if (LEVELS[req.user.role] < LEVELS[role]) return res.status(401).end();
    return next();
  }
}

0

J'utilise cette solution. Je reçois un jeton jwt dans la demande de corps et j'obtiens des informations sur le rôle à partir de là

//roleMiddleware.js

const checkRole = role => {
    
    return (req, res, next) => {
        if (req.role == role) {
            console.log(`${role} role granted`)
            next()
        } else {
            res.status(401).send({ result: 'error', message: `No ${role} permission granted` })
        }
    }
}

module.exports = { checkRole }

Donc, j'utilise d'abord le middleware d'authentification pour savoir si est un utilisateur valide, puis le middleware de rôle pour savoir si l'utilisateur a accès à la route api

// router.js

router.post('/v1/something-protected', requireAuth, checkRole('commercial'), (req, res) => {
    // do what you want...
})

J'espère être utile

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.