Створення проміжного програмного забезпечення expressjs, яке приймає параметри


106

Я намагаюся створити проміжне програмне забезпечення, яке може приймати параметри. Як це можна зробити?

приклад

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

})

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

   next();
}

42
Ха, ви задали моє точне запитання щодо мого точного сценарію, але 6 років тому. ТАК чудово.
aero

6
@aero точно те саме, що я шукав: D
Джесон Діас

4
@aero 7 років по тому я шукаю саме ту саму: D
jean d'arme

4
@aero 7 років тому я шукаю саме те саме!
sidd

4
@aero 8 ~ років потому я шукаю саме те саме! \ o /
Ítalo Sousa

Відповіді:


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

Я також хочу переконатися, що я не роблю кілька копій однієї і тієї ж функції:

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

9
Другий метод кешує параметри, які або не можуть бути бажаною поведінкою.
Pier-Luc Gendreau

1
@ Джонатан Онг, чи можете ви пояснити друге визначення функції? Що там відбувається? Я не розумію, що наступний рядок повертає HasRole [роль] || (HasRole [role] = function (req, res, next) {
Рафай Хасан,

1
@JonathanOng, не могли б ви пояснити другий приклад трохи більше для тих, хто не знає вузла так добре? (включаючи мене). Коли можна отримати кілька копій однієї і тієї ж функції, і коли це може спричинити проблеми? Дякую.
Дейв

без кешування, app.get('/a', hasRole('admin'))і app.get('/b', hasRole('admin'))створить нове закриття для кожного hasRole. це не має великого значення реалістично, якщо у вас дійсно велика програма. я просто кодую це за замовчуванням.
Джонатан Онг

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();
};

Хороша і проста ідея. Проміжне програмне забезпечення насправді є звичайною функцією. Чому б не передати йому інші значення. Будь ласка, включіть req, res та next у першу функцію.
зеверо

1
Хоча код часто говорить сам за себе, добре додати до свого коду якесь пояснення. Це з’явилося в черзі огляду, як правило, відповіді лише на код.
Буде

Я думав про такий підхід перед тим, як відвідати SO, але подумав: "Ме, є, звичайно, кращий спосіб". Після відвідування я бачу, що це справді найпростіший та найефективніший спосіб.
Fusseldieb

3

Якщо у вас не надто багато випадків або якщо роль НЕ є рядком:

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

})

елегантне рішення
Леос Літерак

2

Якщо у вас є різні рівні дозволів, ви можете структурувати їх так:

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

Я використовую це рішення. Я отримую маркер jwt у запиті body та отримую інформацію про ролі звідти

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

Отже, спочатку я використовую проміжне програмне забезпечення auth, щоб дізнатись, чи є дійсним користувачем, а потім проміжне програмне забезпечення ролі, щоб дізнатися, чи має користувач доступ до маршруту api

// router.js

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

Я сподіваюся бути корисним

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.