企業管理系統先後端分離架構設計 系列一 權限模型篇

取這個標題,可能有點膨脹,畢竟看到「架構」這個詞,不少人想到的多是大項目,涉及到分佈式,高併發等一些高大上的東西。html

前段時間分別用vue和react寫了兩個後臺管理系統的模板vue-quasar-admin3YAdmin。兩個項目中都實現了基於RBAC的權限控制。由於本職工做是後端開發,比較清楚權限控制一個管理系統應該必須具有的核心功能,並且是能夠作到通用的。打算寫寫關於管理系統先後端分離方面的文章,也是作一個知識的總結,其中會涉及到vue,react,node,.net core等方面的知識。vue

術語描述

  • 用戶(Subject):發起操做的主體
  • 對象(Object):指操做所針對的客體對象,好比文章或評論
  • 權限(Permission):用來指代對某種對象的某一種操做,例如「添加文章的操做」
  • 權限碼:權限的代號,例如用「ARTICLE_ADD」來指代「添加文章的操做」權限

權限有時候也能夠稱爲動做或者功能。好比「添加文章」,既能夠認爲它是一個動做,也能夠認爲它是一個功能。對象也能夠稱爲資源。node

經常使用的權限模型

  • ACL(Access Control List)(訪問控制列表)
  • DAC(Discretionary Access Control)(自主訪問控制)
  • MAC(Mandatory Access Control)(強制訪問控制)
  • RBAC(Role-Based Access Control)(基於角色的訪問控制)
  • ABAC(Attribute-Based Access Control)(基於屬性的訪問控制)

ACL(Access Control List)(訪問控制列表)

ACL是最先也是最基本的一種訪問控制機制,它是用來描述用戶和權限之間關係的數據列表。它的原理很是簡單:每一項資源,都配有一個列表,這個列表記錄的就是哪些用戶能夠對這項資源執行CRUD等操做。當試圖訪問這項資源時,會首先檢查這個列表中是否有關於當前用戶的訪問權限,從而肯定當前用戶能否執行相應的操做。react

例如一個文件對象的 ACL 爲 Alice: read,write; Bob: read,這表明 Alice 對該文件既能讀又能寫,而 Bob 只能讀取。git

因爲ACL的簡單性,使得它幾乎不須要任何基礎設施就能夠完成訪問控制。但同時它的缺點也是很明顯的,因爲須要維護大量的訪問權限列表,ACL在性能上有明顯的缺陷。另外,對於擁有大量用戶與衆多資源的應用,管理訪問控制列表自己就變成很是繁重的工做。github

最開始的ACL定義中,用戶直接和權限掛鉤,數據存儲的是用戶與權限的關聯關係。若是兩個用戶的權限是同樣的,那麼就須要分別存儲這兩個用戶與權限的關聯關係,也是上面所提到的ACL的缺陷。爲了解決這些問題,便有了對ACL設計的改進,相同權限的用戶放到同一個分組裏,分組與權限掛鉤,再也不是用戶直接與權限掛鉤。以及後來出現的RBAC(基於角色的訪問控制),角色與分組也是差很少的概念,角色直接與權限掛鉤,用戶再與角色進行關聯。json

因此,如今通常說ACL,再也不是用戶直接和權限掛鉤的一種權限控制模型,把它看作一個單純的訪問控制列表便可。列表裏維護的多是用戶與權限的關係,也能夠是用戶組與權限的關係,也能夠是角色與權限的關係,甚至是部門,職位等等於權限的關係。後端

ACL是權限體系中的業務規則。RBAC等權限模型要用到ACL才能工做,ACL服務於RBAC等權限模型,其它權限控制體系裏的權限規則也叫ACL。緩存

DAC(Discretionary Access Control)(自主訪問控制)

系統會識別用戶,而後根據被操做對象(Subject)的權限控制列表(ACL: Access Control List)或者權限控制矩陣(ACL: Access Control Matrix)的信息來決定用戶的是否能對其進行哪些操做,例如讀取或修改。 而擁有對象權限的用戶,又能夠將該對象的權限分配給其餘用戶,因此稱之爲「自主(Discretionary)」控制。安全

由於用戶能自主地將本身擁有的權限授予其餘用戶,因此DAC模型能夠任意傳遞權限,用戶能間接得到本不具備的訪問權限,所以DAC模型的安全性較低,不能給系統充分的數據保護。

DAC能夠直接使用ACL的物理模型,區別在於,DAC模型中用戶能夠將本身具有的權限分配給其它用戶(程序裏的操做就是根據用戶ID篩選出權限列表,根據列表爲要分配權限的用戶構造出新的權限列表並保存)

DAC是傳統的UNIX訪問控制模型,也是Windows文件系統的訪問控制模型。

Windows的文件訪問權限的設置中,除了用戶,還有組。這個組與後面要說到的RABC模型的角色有什麼區別呢?

stackoverflow.com/questions/7…

我認爲不必去劃分的太清楚,無論是組仍是角色,都是爲了更好的管理和分配權限在最原始的ACL模型上作的改進。若是有須要,甚至能夠把權限分配到部門,職位上。

MAC(Mandatory Access Control)(強制訪問控制)

MAC是爲了彌補DAC權限控制過於分散的問題而誕生的。在MAC的設計中,每個對象都有一些權限標識,每一個用戶一樣也會有一些權限標識,而用戶可否對該對象進行操做取決於雙方的權限標識的關係,這個限制判斷一般是由系統硬性限制的。訪問時,系統先對用戶的訪問許可級別和資源對象的密級進行比較,再決定用戶是否能夠訪問資源對象。用戶不能改變自身和資源對象的安全級別,只有系統管理員或管理程序才能 控制資源對象和用戶的級別。好比在影視做品中咱們常常能看到特工在查詢機密文件時,屏幕提示須要「沒法訪問,須要一級安全許可」,這個例子中,文件上就有「一級安全許可」的權限標識,而用戶並不具備。

MAC很是適合機密機構或者其餘等級觀念強烈的行業,但對於相似商業服務系統,則由於不夠靈活而不能適用。

MAC能夠繼續使用DAC的模型,可是要對用戶進行等級劃分,好比一級,二級,三級。。。,對對象資源也要作劃分,好比機密,祕密和最高機密。用戶訪問的資源的時候,根據用戶等級與資源訪問級別來作判斷,好比一級用戶只能訪問機密文件,若是訪問的是最高機密文件,系統就會拒絕。這一系列規則是優先於DAC的,若是MAC與DAC混用,要先校驗MAC再校驗DAC。

RBAC(Role-Based Access Control)(基於角色的訪問控制)

ACL的訪問控制機制中,直接維護的是用戶與功能的關係,這一系列的關係就是一個權限列表。當不少的用戶具備相同功能權限的時候,就要進行繁瑣的關聯操做。RBAC就是在用戶與權限之間引入了角色的概念。用戶與角色之間作關聯,權限列表維護的是角色與功能的關係。

RBAC是目前使用最廣泛的權限控制模型。當某些用戶具有相同的權限的時候,只須要爲這些用戶建一個角色,把相應的功能關聯到這個角色上,生成角色的權限列表。當有新的用戶須要相同權限的時候,把用戶關聯到這個角色上便可。而當用檢查或校驗用戶的操做權限的時候,查詢用戶所屬角色的權限列表便可。

固然,RBAC也不是完美的,好比想要爲某個用戶單獨設置某個功能權限,可能須要爲這個功能權限單首創建一個角色,而後把特定的用戶關聯到這個角色上。當想要移除某個用戶的特定功能權限的時候,可能須要從新設置角色的功能權限,把特定功能權限從當前角色中移除,創建新的角色並關聯特定的功能權限,而後再把新角色與相關的用戶作關聯(也能夠直接在特定功能的程序裏校驗操做用戶)

這裏說一個比較常見的RBAC的錯誤的用法:那就是直接使用角色作權限判斷。好比只有角色A才能作文章的刪除操做。

function delPost(postId){
    if(!isRole('A')){
        return false;
    }
}
複製代碼

若是需求該爲角色B也能夠刪除文章。那就必須修改代碼

function delPost(postId){
    if(!isRole('A')&&!isRole('B')){
        return false;
    }
}
複製代碼

正確的作法應該是添加"刪除文章"這個功能,把這個功能關聯到相應的角色上。判斷的時候是根據功能去判斷而不是角色。

function delPost(postId){
    if(!hasPermission('POST_DEL')){
        return false;
    }
}
複製代碼

針對「只有角色A才能作文章的刪除操做」這一需求,把這個刪除功能關聯到角色A上,而後把須要這個操做權限的用戶加入到角色A中便可。當別的角色也須要這個操做權限,把功能關聯到對應角色上便可,不須要再修改代碼。

在RBAC的核心基礎上,還能夠作相應的擴展,好比角色繼承,角色分組之類的,這些擴展都是爲了在必定程度簡化權限管理工做。

ABAC(Attribute-Based Access Control)(基於屬性的權限控制)

RBAC雖然是目前最廣泛的權限控制模型。可是某些狀況下,RBAC是沒法知足而且也實現不了的。好比業務員1和業務員2都屬於業務員角色,都有查看客戶訂單的權限。當有一個需求,要求業務員1只能查看北京地區的客戶的訂單,業務員2只能查看上海的客戶的訂單。這單單使用RBAC是沒法實現。藉助RBAC,可行的作法是,分地區建立角色,而後程序中根據角色作數據的過濾,這種作法缺點以前也提到過,需求變動的時候可能須要每次都修改代碼。

上面業務員查看訂單的例子,地區是訂單的一個屬性,需求就是針對這個地區屬性來作訂單的查詢範圍的權限控制。這種權限控制方式就是ABAC(Attribute-Based Access Control)(基於屬性的權限控制),也被一些人稱爲是權限系統設計的將來。

不一樣於常見的將用戶經過某種方式關聯到權限的方式,ABAC則是經過動態計算一個或一組屬性是否知足某種條件來進行受權判斷的(能夠編寫簡單的邏輯)。屬性一般來講分爲四類:用戶屬性(如用戶年齡),環境屬性(如當前時間),操做屬性(如讀取)和對象屬性(如一篇文章,又稱資源屬性),因此理論上可以實現很是靈活的權限控制,幾乎能知足全部類型的需求。

例如規則:「容許全部班主任在上課時間自由進出校門」這條規則,其中,「班主任」是用戶的角色屬性,「上課時間」是環境屬性,「進出」是操做屬性,而「校門」就是對象屬性了。

ABAC很是的靈活,可是實現也是很是的難。這其中涉及到邏輯的動態執行,數據動態過濾等,更加具體就是動態拼接SQL語句(使用ORM的話就是動態組裝對應ORM的查詢語句)。

感興趣的能夠在Github上搜索ABAC,看看不一樣語言是否已經有現成的解決方案。下面說說我學習到的一種實現方式:

仍是業務員查看訂單的例子,在RBAC的基礎上,擴展一個實體規則,訂單就是實體,也就是針對訂單設置一系列的規則。規則存儲格式能夠是json也能夠是xml,甚至是Sql語句,能解析便可。好比北京地區這個規則:

{
    "regionId":1
}
複製代碼

上海地區:

{
    "regionId":3
}
複製代碼

regionId 就是系統裏對應區域的Id,也是訂單或訂單相關表的某個字段。

保存這個規則的時候,規則內容(就是上面的json),規則實體(也就是訂單,代表這個規則是針對訂單的)是必須的。也能夠加上這個規則是適用增刪改查中的一種或多種。

建立好實體的規則,將規則與角色作關聯,也就是將北京地區的規則關聯到北京地區角色上,上海地區的規則關聯到上海地區角色上。

後端作權限校驗的時候,仍是先按RBAC模型的控制方式進行校驗(是否具有訂單查看權限),而後根據當前操做對象(也就是實體),取出用戶所屬角色關聯的對應實體的規則。而後解析規則,動態拼接Sql或者ORM語句。

沒作地區限制(或沒配置規則)的時候,Sql多是

select userId,orderNo,createdDate from T_Order
複製代碼

配置了規則,解析拼接後可能就是

select userId,orderNo,createdDate from T_Order where regionId=1
複製代碼

這裏是針對地區這個屬性實現了動態的權限控制。實際開發過程當中,要控制的東西是很是多了,查看字段的控制,數據範圍的控制。要知足這些複雜的控制,須要制定一套完整的規則,以及針對規則編寫相應的解析程序。好比根據配置的規則,最後解析出來多是各類Sql語句:<,>,=,like,in,not in等等。

能夠看出,要真正的落地實現ABAC是多麼的複雜。每次都要解析規則,對程序的性能也形成的影響,就算使用緩存,命中的機率也是很是的小,由於不少因素都是動態的。

因此,若是須要根據屬性作權限判斷的場景不是不少的話,仍是建議使用RBAC,而後程序中作判斷比較省事省力。

總結

ACL早期定義中是一種權限控制機制,這種機制直接維護的是用戶與功能的關係,功能就是針對對象定義的一些操做,好比增刪改查的等。用戶與功能的關係列表也稱爲權限列表或訪問控制列表,如今說ACL,通常就是指這個權限列表或訪問控制列表,可是裏面維護的關係不必定是用戶與功能的關係,在RBAC中維護的就是角色與功能的關係。

RBAC在ACL的基礎上加入了角色的概念,權限列表或訪問控制列表裏維護的再也不是用戶與功能的關係,而是角色與功能的關係。ACL能夠和RBAC混着用,既能夠在角色上設置權限,也能夠直接給用戶設置權限,更加靈活。藉助角色的思想,能夠在用戶組,組織,職位等等上設置權限,以便更好的作好權限管理,也就是將權限設置從單一個體轉移到某一類組合上。

ABAC很是的靈活,也很是的難實現。

參考文章

權限系統設計模型分析

Authorization Models: ACL, DAC, MAC, RBAC, ABAC

相關文章
相關標籤/搜索