Creazione di un middleware expressjs che accetta parametri


105

Sto cercando di creare un middleware in grado di accettare parametri. Come si può fare?

esempio

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

})

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

   next();
}

41
Ha, hai fatto la mia domanda esatta per il mio scenario esatto, ma 6 anni prima. COSÌ è fantastico.
aero

6
@aero esattamente la stessa cosa che stavo cercando: D
Jeson Dias

4
@aero 7 anni dopo sto cercando lo stesso identico: D
jean d'arme

4
@aero 7+ anni dopo sto cercando la stessa identica cosa!
sabato

4
@aero 8 ~ anni dopo sto cercando la stessa identica cosa! \ o /
Ítalo Sousa

Risposte:


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

Voglio anche assicurarmi di non fare più copie della stessa funzione:

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

9
Il secondo metodo memorizza nella cache i parametri, che possono essere o meno il comportamento desiderato.
Pier-Luc Gendreau

1
@ Jonathan Ong, puoi spiegare la seconda definizione della funzione. Cosa sta succedendo lì? Non capisco la riga seguente return HasRole [role] || (HasRole [role] = function (req, res, next) {
Rafay Hassan

1
@ JonathanOng potresti spiegare un po 'di più il secondo esempio per coloro che non conoscono il nodo così bene? (incluso me). Quando è possibile ottenere più copie della stessa funzione e quando ciò può causare problemi? Grazie.
Dave

senza memorizzazione nella cache app.get('/a', hasRole('admin'))e app.get('/b', hasRole('admin'))creerebbe una nuova chiusura per ciascuno hasRole. questo non ha molta importanza realisticamente a meno che tu non abbia un'applicazione molto grande. codice in questo modo per impostazione predefinita.
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();
};

Idea buona e semplice. Il middleware è davvero solo una funzione normale. Perché non passargli altri valori. Si prega di includere req, res e next nella prima funzione.
zevero

1
Sebbene il codice spesso parli da solo, è bene aggiungere qualche spiegazione al codice. Questo è apparso nella coda di revisione, come tendono a fare le risposte di solo codice.
Will

Stavo pensando a quell'approccio prima di visitare SO, ma ho pensato "Meh, c'è sicuramente un modo migliore". Dopo la visita vedo che questo è davvero il modo più semplice ed efficace.
Fusseldieb

3

In alternativa, se non hai troppi casi o se il ruolo NON è una stringa:

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) {

})

soluzione elegante
Leos Literak

2

Se disponi di vari livelli di autorizzazione, puoi strutturarli in questo modo:

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

Uso questa soluzione. Ricevo un token jwt in body req e ottengo informazioni sul ruolo da 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 }

Quindi prima utilizzo il middleware di autenticazione per sapere se è un utente valido, quindi il middleware del ruolo per sapere se l'utente ha accesso alla route API

// router.js

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

Spero di esserti stato utile

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.