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

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

1. 前言

歡迎閱讀 Spring Security 實戰干貨 系列文章 。對于受限的訪問資源,并不是對所有認證通過的用戶開放的。比如 A 用戶的角色是會計,那么他就可以訪問財務相關的資源。 B 用戶是人事,那么他只能訪問人事相關的資源。我們在[]() 一文中也對基于角色的訪問控制的相關概念進行了探討。在實際開發中我們如何對資源進行角色粒度的管控呢?今天我來告訴你 Spring Security 是如何來解決這個問題的。

2. 將角色寫入 UserDetails

我們使用 UserDetailsService 加載 UserDetails 時也會把用戶的 GrantedAuthority` 權限集寫入其中。你可以將角色持久化并在這個點進行注入然后配置訪問策略,后續的問題交給 Spring Security

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

我們可以通過配置 WebSecurityConfigurerAdapter 中的 HttpSecurity 來控制接口的角色訪問。

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

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

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

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

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

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

如果一個接口開放給多個角色,比如 /foo/test 開放給了 ROLE_APPROLE_ADMIN 可以這么寫:

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

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

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").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

原文 

https://segmentfault.com/a/1190000020996401

本站部分文章源于互聯網,本著傳播知識、有益學習和研究的目的進行的轉載,為網友免費提供。如有著作權人或出版方提出異議,本站將立即刪除。如果您對文章轉載有任何疑問請告之我們,以便我們及時糾正。

PS:推薦一個微信公眾號: askHarries 或者qq群:474807195,里面會分享一些資深架構師錄制的視頻錄像:有Spring,MyBatis,Netty源碼分析,高并發、高性能、分布式、微服務架構的原理,JVM性能優化這些成為架構師必備的知識體系。還能領取免費的學習資源,目前受益良多

轉載請注明原文出處:Harries Blog? » Spring Security 實戰干貨:基于配置的接口角色訪問控制

贊 (0)
分享到:更多 ()

評論 0

  • 昵稱 (必填)
  • 郵箱 (必填)
  • 網址
2013平特肖公式