2017-05-27 26 views
0

我正在嘗試爲我的Express應用程序構建一種基於數據庫的ACL。我目前在數據庫中的權限表包含類似的東西:反向匹配到數據庫條目的快速路由

  • 資源:*
  • 方法:*
  • 角色ID:1
  • isAllowed:true

  • 資源:/users
  • 方法:GET
  • 角色ID:2
  • isAllowed:false

  • 資源:/users/id/*
  • 方法:GET
  • 個角色ID:2
  • isAllowed:true

我的目標是建立它檢查請求對象,並允許或拒絕基於在數據庫中的規則的路徑的中間件。我的實際問題是,如何匹配/users/id/1與數據庫條目/users/id/*?如果我使用數據庫條目作爲我的正則表達式的基礎,那麼/users/id/1顯然是匹配的,但是,我認爲爲每個請求抽取和測試所有數據庫條目並不實際。您認爲根據請求的URL從數據庫中獲取正確規則的最佳方法是什麼?

謝謝你的時間!

回答

0

OK,有點思考和研究後,我發現,你可以在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() 
    }) 
    }) 
}