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();
}
Vartan Arabyan
la source
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();
  })
}
Jonathan Ong
la source
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();
};
chovy
la source
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) {

})
zevero
la source
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();
  }
}
asdf
la source
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

Jarraga
la source