1. 程式人生 > 程式設計 >Spring Security 中細化許可權粒度的方法

Spring Security 中細化許可權粒度的方法

有小夥伴表示微人事(https://github.com/lenve/vhr)的許可權粒度不夠細。不過鬆哥想說的是,技術都是相通的,明白了 vhr 中許可權管理的原理,在此基礎上就可以去細化許可權管理粒度,細化過程和還是用的 vhr 中用的技術,只不過設計層面重新規劃而已。

當然今天我想說的並不是這個話題,主要是想和大家聊一聊 Spring Security 中許可權管理粒度細化的問題。因為這個問題會涉及到不同的許可權管理模型,今天和小夥伴們聊一聊~

1.許可權管理模型

要想將細化許可權粒度,我們不可避免會涉及到一些許可權模型,例如 ACL、RBAC、DAC、MAC 以及 ABAC、PBAC 等。

在這些眾多的許可權模型中,我們使用較多的是 RBAC,ACL 也有一些專案在使用,另外幾種則使用相對較少。因此鬆哥這裡重點和大家介紹 ACL 和 RBAC。

1.1 ACL

ACL 是一種比較古老的許可權控制模型。英文全稱是 Access Control List,中文稱作訪問控制列表,這是一種面向資源的訪問控制模型,所有的許可權配置都是針對資源的。

它的原理是這樣:

對於系統中的每一個資源,都會配置一個訪問列表,這個列表中記錄了使用者/角色對於資源的 CURD 許可權,當系統需要訪問這些資源時,會首先檢查列表中是否存在當前使用者的訪問許可權,進而確定當前使用者是否可以執行相應的操作。

ACL 的使用非常簡單,搞明白它的原理自己分分鐘就能實現。但是 ACL 有一個明顯的缺點,就是需要維護大量的訪問許可權列表。大量的訪問控制列表帶來的問題就是效能下降以及維護複雜。

1.2 RBAC

RBAC(Role-based access control)是一種以角色為基礎的訪問控制,也是目前使用較多的一種許可權模型,它有多種不同的變體,鬆哥後面會專門寫一篇文章來介紹 RBAC,這裡僅簡單科普下。

RBAC 許可權模型將使用者按角色進行歸類,通過使用者的角色來確定使用者對某項資源是否具備操作許可權。RBAC 簡化了使用者與許可權的管理,它將使用者與角色關聯、角色與許可權管理、許可權與資源關聯,這種模式使得使用者的授權管理變得非常簡單和易於維護。

1.3 其他

下面這些使用常見較少,小夥伴們做一個瞭解即可,感興趣的小夥伴也可以自行研究下。

  • ABAC:這是一種基於屬性的訪問控制。
  • PBAC:這是一種基於策略的訪問控制。
  • DAC:除了許可權控制,主體也可以將許可權授予其他主體。
  • MAC:資源可以被哪些類別的主體進行哪些操作,主體可以對哪些等級的資源進行哪些操作,這兩個條件同時滿足時,允許訪問。

2.ACL

接下來鬆哥要和大家仔細介紹一下 ACL 這種許可權模型,RBAC 我後面專門寫文章介紹,本文先不做討論。

Acl 的全稱是 Access Control List,也就是我們所說的訪問控制列表,是用以控制物件的訪問許可權的。Acl 的一個核心思路就是將某個物件的某種許可權授予某個使用者或某種角色,它們之間的關係是多對多,即一個使用者/角色可以具備某個物件的多種許可權,某個物件的許可權也可以被多個使用者/角色所持有。

舉個簡單例子:

現在有一個 User 物件,針對該物件有查詢、修改、刪除等許可權,可以將這些許可權賦值給某一個使用者,也可以將這些許可權賦值給某一個角色,當用戶具備這些角色時就具有執行相應操作的許可權。

從這個角度看,Acl 是一種粒度非常細的許可權控制,它就是專門控制某一個物件的操作許可權。所有的這些許可權都記錄在資料庫中,這帶來了另外一個問題就是需要維護的許可權資料量非常龐大,不利於後期擴充套件。當然,對於一個簡單的系統,使用 Acl 還是可以的,沒有任何問題。

2.1 核心概念

接下來我們來看看 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 主要有兩類實現介面:

  • JdbcAclService
  • JdbcMutableAclService

前者主要是針對 Acl 的查詢操作,後者支援 Acl 的新增、更新以及刪除等操作。我們常用的是 JdbcMutableAclService。

至此,Acl 中一些核心概念就和小夥伴們介紹完了。

2.2 Acl 資料表

上面提到的物件資料,都需要對應的資料表來維護,在 spring-security-acl 依賴中,為這些資料表都提供了指令碼。

Spring Security 中細化許可權粒度的方法

可以看到,針對不同型別的資料庫,都有對應的指令碼。

這裡主要涉及到四張表,接下來鬆哥以 MySQL 指令碼為例,來分別介紹每張表的作用及其欄位的含義。

acl_class

acl_class 是用來儲存物件型別的全路徑,如下:

Spring Security 中細化許可權粒度的方法

這裡的 id 自增長,class 中儲存的是相應物件的全路徑名。

acl_sid

acl_sid 表用來儲存 Sid 的。

Spring Security 中細化許可權粒度的方法

根據前面的介紹,存在兩種型別的 Sid,GrantedAuthoritySid 和 PrincipalSid。所以這裡的 principal 欄位表示該 Sid 是哪種型別的。

acl_object_identity

acl_object_identity 用來儲存需要進行訪問控制的物件資訊。

Spring Security 中細化許可權粒度的方法

  • object_id_class:關聯 acl_class.id。
  • object_id_identity:需要控制的物件的 id。
  • parent_object:父物件 ID,關聯一條 acl_object_identity 記錄。
  • owner_sid:這個 acl 記錄擁有者的 sid。
  • entries_inheriting:是否需要繼承父物件的許可權。

簡單來說,這個表中的 object_id_class 和 object_id_identity 欄位鎖定了你要進行許可權控制的物件,具體如何控制呢?則要看 acl_entry 中的關聯關係了。

acl_entry

這個表單純看資料,一堆數字。

Spring Security 中細化許可權粒度的方法

鬆哥來捋一下,大家就懂了。

  • acl_object_identity:關聯 acl_object_identity.id。
  • ace_order:許可權順序。
  • acl_object_identity 和 ace_order 的組合要唯一。
  • sid:關聯 acl_sid.id。
  • 這條許可權記錄關聯哪個使用者/角色。
  • mask:許可權掩碼。
  • granting:表示當前記錄是否生效。
  • audit_success/audit_failure:審計資訊。

簡單來說,acl_entry 中的一條記錄,關聯了一個要操作的物件(acl_object_identity 和 ace_order 欄位),關聯了 Sid(sid 欄位),也描述了許可權(mask),將許可權涉及到的東西都在該欄位中整合起來了。

3.小結

好啦,這就本文和小夥伴們科普一下 ACL 的概念,下篇文章鬆哥通過一個完整的案例來和小夥伴們演示具體用法~

參考資料:

https://blog.gaoyuexiang.cn/2020/07/02/spring-security-acl-conception-and-component

https://www.iteye.com/blog/elim-2269021

到此這篇關於Spring Security 中細化許可權粒度的方法的文章就介紹到這了,更多相關Spring Security 細化許可權粒度內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!