Spring Security 實戰乾貨:基於配置的接口角色訪問控制

1. 前言

歡迎閱讀 Spring Security 實戰乾貨 系列文章 。對於受限的訪問資源,並非對全部認證經過的用戶開放的。好比 A 用戶的角色是會計,那麼他就能夠訪問財務相關的資源。B 用戶是人事,那麼他只能訪問人事相關的資源。咱們在RBAC概念 一文中也對基於角色的訪問控制的相關概念進行了探討。在實際開發中咱們如何對資源進行角色粒度的管控呢?今天我來告訴你 Spring Security 是如何來解決這個問題的。html

2. 將角色寫入 UserDetails

咱們使用 UserDetailsService 加載 UserDetails 時也會把用戶的 GrantedAuthority 權限集寫入其中。你能夠將角色持久化並在這個點進行注入而後配置訪問策略,後續的問題交給 Spring Securityjava

3. 在 HttpSecurity 中進行配置角色訪問控制

咱們能夠經過配置 WebSecurityConfigurerAdapter 中的 HttpSecurity 來控制接口的角色訪問。spring

3.1 經過判斷用戶是否持有角色來進行訪問控制

httpSecurity.authorizeRequests().antMatchers("/foo/test").hasRole("ADMIN")安全

表示 持有 ROLE_ADMIN 角色的用戶才能訪問 /foo/test 接口。注意:hasRole(String role) 方法入參不能攜帶前綴 ROLE_ 。咱們來查看 SecurityExpressionRoot 中相關源碼:spa

public final boolean hasRole(String role) {
		return hasAnyRole(role);
	}

複製代碼

很明顯 hasRole 方法源於 hasAnyRole (持有任何其中角色之一,就能知足訪問條件,用於一個接口開放給多個角色訪問時) :code

public final boolean hasAnyRole(String... roles) {
		return hasAnyAuthorityName(defaultRolePrefix, roles);
	}
複製代碼

若是一個接口開放給多個角色,好比 /foo/test 開放給了 ROLE_APPROLE_ADMIN 能夠這麼寫:cdn

httpSecurity.authorizeRequests().antMatchers("/foo/test").hasAnyRole("APP","ADMIN")htm

hasAnyRole 方法最終的實現爲 hasAnyAuthorityName(String prefix, String... roles):blog

private boolean hasAnyAuthorityName(String prefix, String... roles) {
		Set<String> roleSet = getAuthoritySet();

		for (String role : roles) {
			String defaultedRole = getRoleWithDefaultPrefix(prefix, role);
			if (roleSet.contains(defaultedRole)) {
				return true;
			}
		}

		return false;
	}
複製代碼

上面纔是根本的實現, 須要一個 prefix 和每個 role 進行拼接,而後用戶的角色集合 roleSet 中包含了就返回true 放行,不然就 false 拒絕。默認的 prefixdefaultRolePrefix= ROLE_接口

3.2 經過判斷用戶的 GrantedAuthority 來進行訪問控制

咱們也能夠經過 hasAuthorityhasAnyAuthority 來斷定。 其實底層實現和 hasAnyRole 方法同樣,只不過 prefixnull 。也就是你寫入的 GrantedAuthority 是什麼樣子的,這裏傳入參數的就是什麼樣子的,再也不受 ROLE_ 前綴的制約。

2.1 章節的寫法等同以下的寫法:

httpSecurity.authorizeRequests().antMatchers("/foo/test").hasAuthority("ROLE_ADMIN")

httpSecurity.authorizeRequests().antMatchers("/foo/test").hasAnyAuthority("ROLE_APP","ROLE_ADMIN")

4. 匿名訪問

匿名身份驗證的用戶和未經身份驗證的用戶之間沒有真正的概念差別。Spring Security 的匿名身份驗證只是爲您提供了一種更方便的方式來配置訪問控制屬性。全部的匿名用戶都持有角色 ROLE_ANONYMOUS 。因此你可使用 2.12.2 章節的方法來配置匿名訪問:

httpSecurity.authorizeRequests().antMatchers("/foo/test").hasAuthority("ROLE_ANONYMOUS")

你也能夠經過如下方式進行配置:

httpSecurity.authorizeRequests().antMatchers("/foo/test").anonymous()

5. 開放請求

開放請求能夠這麼配置:

httpSecurity.authorizeRequests().antMatchers("/foo/test").permitAll()

6. permitAll 與 anonymous 的一些探討

開放請求 其實一般狀況下跟 匿名請求 有交叉。它們的主要區別在於: 當前的 AuthenticationnullpermitAll 是放行的,而 anonymous 須要 AuthenticationAnonymousAuthenticationToken 。這裏是比較難以理解的,下面是來自 Spring 文檔中的一些信息:

一般,採用「默認拒絕」的作法被認爲是一種良好的安全作法,在該方法中,您明確指定容許的內容,並禁止其餘全部內容。定義未經身份驗證的用戶能夠訪問的內容的狀況與此相似,尤爲是對於Web應用程序。許多站點要求用戶必須經過身份驗證才能使用少數幾個URL(例如,主頁和登陸頁面)。在這種狀況下,最簡單的是爲這些特定的URL定義訪問配置屬性,而不是爲每一個受保護的資源定義訪問配置屬性。換句話說,有時很高興地說默認狀況下須要ROLE_SOMETHING,而且只容許該規則的某些例外,例如應用程序的登陸,註銷和主頁。您還能夠從過濾器鏈中徹底忽略這些頁面,從而繞過訪問控制檢查, 這就是咱們所說的匿名身份驗證。

使用 permitAll() 將配置受權,以便在該特定路徑上容許全部請求(來自匿名用戶和已登陸用戶),anonymous() 主要是指用戶的狀態(是否登陸)。基本上,直到用戶被「認證」爲止,它就是「匿名用戶」。就像每一個人都有「默認角色」同樣。

7. 總結

基於配置來解決基於角色的訪問控制是經常使用的方案之一。也是最容易入門的 **Spring Security ** 訪問控制技術。下一期咱們將介紹基於方法的訪問控制。敬請關注 felord.cn。

關注公衆號:Felordcn獲取更多資訊

我的博客:https://felord.cn

相關文章
相關標籤/搜索