1. 程式人生 > >企業管理系統前後端分離架構設計 系列一 權限模型篇

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

-m 權限設置 auto enc 根據 當前 美的 機構 sql語句

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

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

術語描述

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

權限有時候也可以稱為動作或者功能。比如“添加文章”,既可以認為它是一個動作,也可以認為它是一個功能。對象也可以稱為資源。

常用的權限模型

  • 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等操作。當試圖訪問這項資源時,會首先檢查這個列表中是否有關於當前用戶的訪問權限,從而確定當前用戶可否執行相應的操作。

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

由於ACL的簡單性,使得它幾乎不需要任何基礎設施就可以完成訪問控制。但同時它的缺點也是很明顯的,由於需要維護大量的訪問權限列表,ACL在性能上有明顯的缺陷。另外,對於擁有大量用戶與眾多資源的應用,管理訪問控制列表本身就變成非常繁重的工作。

技術分享圖片

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

所以,現在一般說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模型的角色有什麽區別呢?

https://stackoverflow.com/questions/7770728/group-vs-role-any-real-difference

我認為沒必要去劃分的太清楚,不管是組還是角色,都是為了更好的管理和分配權限在最原始的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

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