将快速路由反向匹配到数据库条目

Reverse matching Express routes to database entries

我正在尝试为我的 Express 应用程序构建一种基于数据库的 ACL。我目前在数据库中有一个权限 table,其中包含类似的内容:



我的目标是构建一个中间件来检查请求对象并根据数据库中的规则允许或拒绝路由。我的实际问题是,如何将 /users/id/1 与数据库条目 /users/id/* 匹配?如果我使用数据库条目作为我的正则表达式的基础,那么 /users/id/1 显然是匹配的,但是,我认为为每个请求提取和测试所有数据库条目是不切实际的。您认为根据请求的 URL 从数据库中获取正确规则的最佳方法是什么?

感谢您的宝贵时间!

好的,经过一些思考和研究,我发现你可以在 MySQL 查询中使用正则表达式,所以我想出了这个中间件(我正在使用 Sequelize):

module.exports = function (req, res, next) {
  // If a wildcard is in place, skip the rest
  return models.Permissions.findAll({
    where: {
      resource: '*',
      GID: req.session.role,
      isAllowed: 1
    }
  }).then(function (result) {
    if (result[0]) {
      return next()
    }

    // If the URL contains more than one element, replace the last item with [item, *]
    // to match eventual wildcards in the database entries
    let urlItems = req.url.split('/').filter(Boolean)
    let url = req.url
    if (urlItems.length > 1) {
      let lastItem = '[' + urlItems[urlItems.length - 1] + ', *]'
      url = req.url.split('/')
      url[url.length - 1] = lastItem
      url = url.join('/')
    }

    let query = 'SELECT * FROM Permissions '
    query += 'WHERE resource RLIKE "^' + url + '?$" '
    query += 'AND GID = ' + req.session.role

    return models.sequelize.query(query, {
      type: models.sequelize.QueryTypes.SELECT
    }).then(function (result) {
      let policy = result[0]

      function return403 () {
        res.status(403).send('Forbidden')
      }

      // Forbid everything by default
      if (!policy) {
        return403()
        return
      }

      let methods = policy.method.toUpperCase().split(' ')

      // Forbid all methods which are not allowed
      if (policy.method === '*' || methods.includes(req.method)) {
        if (!policy.isAllowed) {
          return403()
          return
        }
      }

      // When other methods are explicitly allowed, forbid everything else
      if (policy.method !== '*' && !methods.includes(req.method) && policy.isAllowed) {
        return403()
        return
      }

      // Standard behaviour: allow explicitly allowed methods (or *) that are allowed.
      next()
    })
  })
}