Tworzenie oprogramowania pośredniczącego Expressjs, które akceptuje parametry

110

Próbuję utworzyć oprogramowanie pośredniczące, które może akceptować parametry. Jak można to zrobić?

przykład

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

})

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

   next();
}
Vartan Arabyan
źródło
43
Ha, zadałeś moje dokładne pytanie dotyczące mojego dokładnego scenariusza, ale 6 lat wcześniej. SO jest niesamowity.
aero
6
@aero dokładnie to samo, czego szukałem: D
Jeson Dias
4
@aero 7 lat później szukam dokładnie tego samego: D
jean d'arme
4
@aero 7+ lat później szukam dokładnie tego samego!
sidd
4
@aero 8 ~ lat później szukam dokładnie tego samego! \ o /
Ítalo Sousa

Odpowiedzi:

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

Chcę się również upewnić, że nie wykonuję wielu kopii tej samej funkcji:

function HasRole(role) {
  return HasRole[role] || (HasRole[role] = function(req, res, next) {
    if (role !== req.user.role) res.redirect(...);
    else next();
  })
}
Jonathan Ong
źródło
9
Druga metoda buforuje parametry, które mogą być pożądane lub nie.
Pier-Luc Gendreau
1
@Jonathan Ong, czy możesz wyjaśnić drugą definicję funkcji. Co tam się dzieje? Nie rozumiem następującego zwrotu linii HasRole [rola] || (HasRole [role] = function (req, res, next) {
Rafay Hassan,
1
@JonathanOng Czy mógłbyś trochę dokładniej wyjaśnić drugi przykład tym, którzy nie znają węzła tak dobrze? (w tym mnie). Kiedy można uzyskać wiele kopii tej samej funkcji i kiedy może to powodować problemy? Dzięki.
Dave
bez buforowania app.get('/a', hasRole('admin'))i app.get('/b', hasRole('admin'))utworzy nowe zamknięcie dla każdego hasRole. realistycznie nie ma to większego znaczenia, chyba że masz naprawdę dużą aplikację. po prostu domyślnie koduję w ten sposób.
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
źródło
Dobry i prosty pomysł. Oprogramowanie pośredniczące to naprawdę zwykła funkcja. Dlaczego nie przekazać mu innych wartości. W pierwszej funkcji proszę uwzględnić req, res i next.
zevero
1
Chociaż kod często mówi sam za siebie, dobrze jest dodać do kodu wyjaśnienia. Pojawiło się to w kolejce recenzji, tak jak zwykle odpowiedzi zawierające tylko kod.
Will
Myślałem o tym podejściu przed wizytą w SO, ale pomyślałem: „Meh, z pewnością jest lepszy sposób”. Po wizycie widzę, że to naprawdę najprostszy, najbardziej skuteczny sposób.
Fusseldieb
4

Alternatywnie, jeśli nie masz zbyt wielu przypadków lub jeśli rola NIE jest ciągiem znaków:

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
źródło
eleganckie rozwiązanie
Leos Literak
2

Jeśli masz różne poziomy uprawnień, możesz je uporządkować w ten sposób:

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
źródło
0

Używam tego rozwiązania. Otrzymuję token jwt w body req i stamtąd otrzymuję informacje o roli

//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 }

Najpierw używam oprogramowania pośredniego uwierzytelniania, aby wiedzieć, czy jest prawidłowym użytkownikiem, a następnie oprogramowania pośredniczącego roli, aby wiedzieć, czy użytkownik ma dostęp do trasy interfejsu API

// router.js

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

Mam nadzieję, że będę przydatny

jarraga
źródło