有小夥伴表示微人事(https://github.com/lenve/vhr)...。不過鬆哥想說的是,技術都是相通的,明白了 vhr 中權限管理的原理,在此基礎上就能夠去細化權限管理粒度,細化過程和仍是用的 vhr 中用的技術,只不過設計層面從新規劃而已。java
固然今天我想說的並非這個話題,主要是想和你們聊一聊 Spring Security 中權限管理粒度細化的問題。由於這個問題會涉及到不一樣的權限管理模型,今天和小夥伴們聊一聊~git
要想將細化權限粒度,咱們不可避免會涉及到一些權限模型,例如 ACL、RBAC、DAC、MAC 以及 ABAC、PBAC 等。github
在這些衆多的權限模型中,咱們使用較多的是 RBAC,ACL 也有一些項目在使用,另外幾種則使用相對較少。所以鬆哥這裏重點和你們介紹 ACL 和 RBAC。spring
ACL 是一種比較古老的權限控制模型。英文全稱是 Access Control List,中文稱做訪問控制列表,這是一種面向資源的訪問控制模型,全部的權限配置都是針對資源的。數據庫
它的原理是這樣:ide
對於系統中的每個資源,都會配置一個訪問列表,這個列表中記錄了用戶/角色對於資源的 CURD 權限,當系統須要訪問這些資源時,會首先檢查列表中是否存在當前用戶的訪問權限,進而肯定當前用戶是否能夠執行相應的操做。性能
ACL 的使用很是簡單,搞明白它的原理本身分分鐘就能實現。可是 ACL 有一個明顯的缺點,就是須要維護大量的訪問權限列表。大量的訪問控制列表帶來的問題就是性能降低以及維護複雜。spa
RBAC(Role-based access control)是一種以角色爲基礎的訪問控制,也是目前使用較多的一種權限模型,它有多種不一樣的變體,鬆哥後面會專門寫一篇文章來介紹 RBAC,這裏僅簡單科普下。設計
RBAC 權限模型將用戶按角色進行歸類,經過用戶的角色來肯定用戶對某項資源是否具有操做權限。RBAC 簡化了用戶與權限的管理,它將用戶與角色關聯、角色與權限管理、權限與資源關聯,這種模式使得用戶的受權管理變得很是簡單和易於維護。code
下面這些使用常見較少,小夥伴們作一個瞭解便可,感興趣的小夥伴也能夠自行研究下。
接下來鬆哥要和你們仔細介紹一下 ACL 這種權限模型,RBAC 我後面專門寫文章介紹,本文先不作討論。
Acl 的全稱是 Access Control List,也就是咱們所說的訪問控制列表,是用以控制對象的訪問權限的。Acl 的一個核心思路就是將某個對象的某種權限授予某個用戶或某種角色,它們之間的關係是多對多,即一個用戶/角色能夠具有某個對象的多種權限,某個對象的權限也能夠被多個用戶/角色所持有。
舉個簡單例子:
如今有一個 User 對象,針對該對象有查詢、修改、刪除等權限,能夠將這些權限賦值給某一個用戶,也能夠將這些權限賦值給某一個角色,當用戶具有這些角色時就具備執行相應操做的權限。
從這個角度看,Acl 是一種粒度很是細的權限控制,它就是專門控制某一個對象的操做權限。全部的這些權限都記錄在數據庫中,這帶來了另一個問題就是須要維護的權限數據量很是龐大,不利於後期擴展。固然,對於一個簡單的系統,使用 Acl 仍是能夠的,沒有任何問題。
接下來咱們來看看 Acl 中一些核心概念。
Sid
Sid 表明了用戶和角色,它有兩種:GrantedAuthoritySid 和 PrincipalSid,前者表明角色,後者表明用戶。在 Spring Security 中,用戶和角色信息都是保存在 Authentication 對象中的,即 Sid 是從 Authentication 對象中提取出來的,提取出來的值是 GrantedAuthoritySid+PrincipalSid,而不是其中某一項,具體的提取方法是 SidRetrievalStrategyImpl#getSids,相關源碼以下:
public List<Sid> getSids(Authentication authentication) { Collection<? extends GrantedAuthority> authorities = roleHierarchy .getReachableGrantedAuthorities(authentication.getAuthorities()); List<Sid> sids = new ArrayList<>(authorities.size() + 1); sids.add(new PrincipalSid(authentication)); for (GrantedAuthority authority : authorities) { sids.add(new GrantedAuthoritySid(authority)); } return sids; }
這個 Sid 你們能夠簡單理解爲當前用戶的權限(這個說法不是很準確,能夠近似理解)。
ObjectIdentity
ObjectIdentity 是一個域對象,這是官方的說法,有點拗口。實際上這就是你要操做的對象。
例如我有一個 User 對象,若是直接去記錄可以對 User 對象執行哪些操做,這就會致使高耦和。因此咱們須要對其解耦,將全部須要操做的對象經過 ObjectIdentity 描述出來,這樣就能確保權限系統不和具體的業務綁定。
ObjectIdentity 中有兩個關鍵方法,getType 和 getIdentifier。通常來講,getType 方法返回真實對象類的全路徑,例如 org.javaboy.acl.model.User
,getIdentifier 方法則返回真實對象的 id,經過這兩個方法,就可以鎖定一個對象。
Acl
看名字就知道,這算是整個系統的核心調度部分。
一個 Acl 對象會關聯一個 ObjectIdentity,一個 Acl 對象還擁有一個 Sid,這個 Sid 表示這個 Acl 是屬於誰的?屬於誰,誰就能夠修改甚至刪除這個 Acl 對象。
AccessControlEntry
AccessControlEntry 簡寫爲 ACE,一個 AccessControlEntry 對象表明一條權限記錄。每個 AccessControlEntry 都對應了一個 Acl,一個 Acl 對象對應多個 AccessControlEntry,有了這層對應關係,至關於就知道這個權限操做的是哪一個對象。
而後 AccessControlEntry 中還包含一個 Sid 和一個 Permission 對象,表示某個 Sid 具有某種權限。
能夠看到,Acl+ACE,就描述出來了某個 Sid 能夠具有某個 ObjectIdentity 的某種 Permission。
Permission
這個就是具體的權限對象。彷佛是受 Linux 影響,它使用了權限掩碼,最多支持 232-1 種權限。
Spring Security 種默認定義了五種:
public class BasePermission extends AbstractPermission { public static final Permission READ = new BasePermission(1 << 0, 'R'); // 1 public static final Permission WRITE = new BasePermission(1 << 1, 'W'); // 2 public static final Permission CREATE = new BasePermission(1 << 2, 'C'); // 4 public static final Permission DELETE = new BasePermission(1 << 3, 'D'); // 8 public static final Permission ADMINISTRATION = new BasePermission(1 << 4, 'A'); // 16 protected BasePermission(int mask) { super(mask); } protected BasePermission(int mask, char code) { super(mask, code); } }
AclService
AclService 接口中主要定義了一些解析 Acl 對象的方法,經過 ObjectIdentity 對象解析出其對應的 Acl。
AclService 主要有兩類實現接口:
前者主要是針對 Acl 的查詢操做,後者支持 Acl 的添加、更新以及刪除等操做。咱們經常使用的是 JdbcMutableAclService。
至此,Acl 中一些核心概念就和小夥伴們介紹完了。
上面提到的對象數據,都須要對應的數據表來維護,在 spring-security-acl 依賴中,爲這些數據表都提供了腳本。
能夠看到,針對不一樣類型的數據庫,都有對應的腳本。
這裏主要涉及到四張表,接下來鬆哥以 MySQL 腳本爲例,來分別介紹每張表的做用及其字段的含義。
acl_class
acl_class 是用來保存對象類型的全路徑,以下:
這裏的 id 自增加,class 中保存的是相應對象的全路徑名。
acl_sid
acl_sid 表用來保存 Sid 的。
根據前面的介紹,存在兩種類型的 Sid,GrantedAuthoritySid 和 PrincipalSid。因此這裏的 principal 字段表示該 Sid 是哪一種類型的。
acl_object_identity
acl_object_identity 用來保存須要進行訪問控制的對象信息。
簡單來講,這個表中的 object_id_class 和 object_id_identity 字段鎖定了你要進行權限控制的對象,具體如何控制呢?則要看 acl_entry 中的關聯關係了。
acl_entry
這個表單純看數據,一堆數字。
鬆哥來捋一下,你們就懂了。
簡單來講,acl_entry 中的一條記錄,關聯了一個要操做的對象(acl_object_identity 和 ace_order 字段),關聯了 Sid(sid 字段),也描述了權限(mask),將權限涉及到的東西都在該字段中整合起來了。
好啦,這就本文和小夥伴們科普一下 ACL 的概念,下篇文章鬆哥經過一個完整的案例來和小夥伴們演示具體用法~
參考資料: