Создание промежуточного программного обеспечения expressjs, принимающего параметры


105

Я пытаюсь создать промежуточное ПО, которое может принимать параметры. Как это может быть сделано?

пример

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

})

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

   next();
}

41
Ха, вы задали мне точный вопрос по моему точному сценарию, но 6 лет назад. ТАК круто.
aero

6
@aero точно то же самое, что я искал: D
Джесон Диас

4
@aero 7 лет спустя я ищу такую ​​же: D
jean d'arme

4
@aero 7+ лет спустя я ищу то же самое!
sidd

4
@aero 8 ~ лет спустя я ищу то же самое! \ o /
talo Sousa

Ответы:


162
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
@ Джонатан Онг, не могли бы вы объяснить второе определение функции. Что там происходит? Я не понимаю следующую строку return HasRole [role] || (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
Хотя код часто говорит сам за себя, полезно добавить к нему некоторые пояснения. Это появилось в очереди на проверку, как обычно бывает в ответах, содержащих только код.
Will

Я думал об этом подходе до посещения 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) {

})

элегантное решение
Leos Literak

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 в теле req и получаю оттуда информацию о ролях

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