基於角色的權限控制(RBAC)是管理用戶對某種資源或操做的權限的通用方法。權限能夠明確指定能夠訪問的資源和操做。基本原理以下:權限將被分配給某個角色,並將該角色分配給某個用戶或者是用戶組,而不是直接分配給某個用戶。面試
將權限與單個用戶關聯起來是一件很複雜的事情,隨着更多的用戶使用系統,維護用戶的權限變得更加困難,且容易出錯。權限的錯誤分配會阻止用戶訪問所需的系統,甚至是容許非受權用戶訪問限制區域或是執行危險操做。spring
在這篇文章中,我會介紹如何對應用開啓權限控制。權限控制的模型有許多種,好比RBAC(基於角色的權限控制),DAC(自由訪問控制)等。雖然文檔中解釋的原則能夠應用於各類模型,但我選擇RBAC做爲參考,由於它被普遍接受而且很是直觀。數組
查看用戶的活動一般只會產生用戶執行的有限數量的操做(如讀取數據,提交表單)。深刻觀察這些用戶的行爲會發現,這些行爲一般一塊兒執行,即執行A操做的用戶每每也會執行B操做。好比,讀取並更新報告,或者是添加和刪除用戶。這些均可以與角色綁定,好比編輯或是帳戶管理員。注意這裏的角色並不必定和職稱或是組織結構綁定,而是以有意義的方式反映相關的用戶操做。當恰當劃分好角色並分配給用戶時,就能夠將權限分配給每一個角色,而非用戶。管理少許角色的權限是一件相對簡單的事情。微信
以下,是沒有角色做爲中介的權限與用戶圖:架構
而以下,則是徹底相同的用戶和權限集,由角色組織:框架
顯而易見,角色使得權限管理更容易了dom
將用戶與羣組綁定是一種更好的實踐。工具
在觀察用戶關於上述角色的行爲模式時,咱們常常發現用戶之間有不少共同之處,好比某一組用戶經常行爲類似--在共同的資源上執行相同的操做。這容許咱們將用戶組織到組中,而後將角色分配給少數組,而不是許多用戶。好比,會發現一組用戶都須要系統管理員權限,所以咱們新建一個名叫帳戶管理員的羣組,將用戶添加到該組並將該角色分配給該組,而不是每一個用戶。spa
在許多系統中,開發人員經過直接在實現方法上指定權限來限制對特定操做的訪問。沒錯,就在代碼上!一般,角色的驗證經過註解添加到須要檢查的方法上,好比這裏提供了一個spring-security的一個範例:設計
@PreAuthorize("hasRole('Editor')") public void update_order(Order order);
在不一樣語言和框架中,這種作法很是常見。雖然很容易實現,但遺憾的是,它在所需角色和動做的實現之間產生了不但願的耦合。想象一下有幾十個方法都須要添加這樣的註解。跟蹤每個角色的有效操做將會變得很艱難,幾乎確定會致使依賴於不許確或過期的文檔,或者更糟糕的是 - 分散在您的應用程序中的未知,非託管權限。
從客戶的角度來看,這種耦合使得沒法修改開發人員事先定義的角色集或者他們的權限,由於更改它意味着每次都必須編譯和打包代碼!這種用戶體驗也許不是咱們的目標。
更好的方式是,首先從要由外部受權機制處理的代碼中提取可能的操做列表,而後,咱們可使代碼不知道角色或任何其餘受權細節,簡單地詢問當前用戶(不管它是否被檢索)是否具備執行特定方法所需的權限(不管在何處定義)。
這容許咱們使用更加通用的註解,以下所示:
@Secured public void update_order(Order order);
角色和權限的映射(即執行特定操做的權限)如今能夠在配置文件中完成,能夠由客戶輕鬆定製!
好比,假設有這樣的一個roles_config.yml文件:
order_manager: - 'create_order' - 'view_order' - 'delete_order' - 'update_order' order_inspector: - 'viewer_order'
由@secured註解的方法回去查詢配置文件肯定當前用戶是否具備執行該操做的權限。這意味着當前用戶必須具備order_manager的角色,而這一點也是很容易配置的。可是,受權機制必須知道如何將每一個權限與代碼中的特定方法相匹配,而且有人必須記錄全部可用的方法(即create_order,view_order等)。
既然方法實現代碼不包含受權細節,整個受權邏輯能夠移動到單獨的獨立模塊。經過使用通用標題(例如註解@secure
),咱們容許修改整個受權機制而不影響應用程序的代碼。例如,能夠將@secure
實現爲基於角色的檢查,但也可使用訪問控制列表(ACL)。好比,檢查當前用戶是否列在訂單的ACL列表中。另外一種解決方案能夠是經過詢問第三方是否容許用戶執行該動做來使用oauth。
REST接口確定更好,或者至少是最容易匹配這個模型的。設計良好的Rest服務經過標準的基於HTTP的API暴露資源和方法,資源經過URI定義,方法經過HTTP動詞(如GET,PUT)等定義。
好比,POST http://www.domain.com/bookings
會建立一本新書,而GET http://www.domain.com/orders/12345
會返回訂單#12345的詳情。這意味着能夠垂手可得的得到資源的名稱和對資源的操做。
除了標準的建模操做以外,REST服務一般是請求流中評估身份驗證和受權的好地方,由於這一般是系統的主要入口點。爲了使訪問控制機制有意義,建議阻止全部其餘到系統的路由,例如直接訪問數據存儲或代碼中的任何遠程調用機制。該架構的另外一個重要優勢是響應過濾,以防某些不該當返回給用戶的數據寫在響應中。
REST服務處理傳入請求,這意味着請求中找到的信息可用於制定訪問控制決策。一些有用的細節是:
全部的資源將會經過REST的URI表示,操做經過HTTP動詞表示,這可以覆蓋全部能被執行且須要驗證的操做。在下面的例子中,定義了三個角色:
order_manager: '/orders': - 'GET' - 'POST' - 'PUT' - 'DELETE' order_editor: '/orders': - 'GET' - 'POST' - 'PUT' order_inspector: '/orders': - 'GET'
因而可知,REST自然可以實現權限控制。經過處理傳入請求,REST服務可以檢索有價值的信息,這些信息能夠移交給單獨的模塊以執行身份驗證和受權。若是用戶被受權在目標資源上執行所請求的方法,則能夠繼續請求處理。不然,在到達任何內部應用程序代碼以前拒絕進一步訪問。
想要了解更多開發技術,面試教程以及互聯網公司內推,歡迎關注個人微信公衆號!將會不按期的發放福利哦~