创建一个接受参数的expressjs中间件


103

我正在尝试创建一个可以接受参数的中间件。如何才能做到这一点?

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

})

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

   next();
}

40
哈,您已经问过我的确切问题了,但是是六年前。太棒了。
航空

6
@aero我一直在寻找相同的东西:D
Jeson Dias

4
@aero 7年后,我正在寻找相同的东西:D
Jean d'arme

4
@aero 7年后,我正在寻找完全一样的东西!
sidd

4
@aero 8年后,我正在寻找完全一样的东西!\ O /
伊塔洛Sousa的

Answers:


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 2014年

1
@Jonathan Ong,请您解释一下该函数的第二个定义。那里发生了什么事?我不明白以下行返回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。
zevero '16

1
虽然代码通常可以说明一切,但是最好在代码中添加一些解释。正如仅提供代码的答案一样,这会在查看队列中弹出。
2016年

在访问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

我用这个解决方案。我在body req中收到一个jwt令牌,并从那里获取角色信息

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

我希望有用

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.