【问题标题】:Creating a expressjs middleware that accepts parameters创建一个接受参数的 expressjs 中间件
【发布时间】:2012-09-26 01:44:23
【问题描述】:

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

例子

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

})

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

   next();
}

【问题讨论】:

  • 哈,你问了我确切的问题,但在 6 年前。太棒了。
  • @aero 与我正在寻找的东西完全相同:D
  • @aero 7 年后我正在寻找完全相同的一个:D
  • @aero 7 多年后我正在寻找完全相同的东西!
  • @aero 8~ 年后我正在寻找完全相同的东西! \o/

标签: node.js express


【解决方案1】:
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();
  })
}

【讨论】:

  • 第二种方法缓存参数,可能不是期望的行为。
  • @Jonathan Ong,你能解释一下函数的第二个定义吗?那里发生了什么?我不明白以下行 return HasRole[role] || (HasRole[role] = function(req, res, next) {
  • @JonathanOng 您能否为那些不了解该节点的人多解释一下第二个示例? (包括我)。什么时候可以获得相同功能的多个副本,什么时候会导致问题?谢谢。
  • 如果没有缓存,app.get('/a', hasRole('admin'))app.get('/b', hasRole('admin')) 将为每个 hasRole 创建一个新的闭包。除非您有一个非常大的应用程序,否则这实际上并不重要。我只是默认这样编码。
  • @Pier-LucGendreau 你说第二种方法缓存参数是什么意思?是否意味着新请求可以从之前的请求中读取req.user.role 的值?
【解决方案2】:
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。
  • 虽然代码通常不言自明,但最好在代码中添加一些解释。这会在审核队列中弹出,因为只有代码的答案往往如此。
  • 在访问 SO 之前我正在考虑这种方法,但我认为“嗯,肯定有更好的方法”。访问后发现,这确实是最简单、最有效的方法。
【解决方案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) {

})

【讨论】:

  • 优雅的解决方案
【解决方案4】:

如果您有不同的权限级别,您可以像这样构建它们:

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

【讨论】:

    【解决方案5】:

    我使用这个解决方案。我在正文 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...
    })
    

    希望对你有用

    【讨论】:

      【解决方案6】:

      既然我们在 2021 年,为什么不使用 ES6 语法?...使用 NodeJS v14.16.1,下面的示例就像一个魅力:-)

      使用快速路由器

      const someFunc = ({ option1, option2 }) =>
       router.get("/", (req, res, next) => {
          
       // code
          
       next();
      });
      
      module.exports = someFunc;
      

      const someFunc = ({ option1, option2 }) =>
           (req, res, next) => {
              
           // code
              
           next();
          };
          
       module.exports = someFunc;
      

      ...然后这样称呼它:

      const someFunc = require('./middlewares/someFunc.js');
      app.use(someFunc({option1: 'test', option2: false ));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-03-02
        • 1970-01-01
        • 1970-01-01
        • 2022-11-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多