1. 概述
在本文中,我們將解釋 Spring Security 中 角色 (Role) 和 授權 (GrantedAuthority) 之間的微妙但重要的區別。有關角色和授權的更詳細信息,請參閲此處。
2. GrantedAuthority
在 Spring Security 中,我們可以將每個 GrantedAuthority 視為一個獨立的權限。例如,可以包括 READ_AUTHORITY、WRITE_PRIVILEGE,甚至 CAN_EXECUTE_AS_ROOT。重要的是要理解的是,名稱是任意的。
當直接使用 GrantedAuthority,例如通過使用像 hasAuthority('READ_AUTHORITY') 這樣的表達式時,我們 以精細的方式限制訪問。
正如你可能已經注意到,我們可以通過使用 authority 來引用 privilege 概念。
3. 擔任權威角色
類似於 Spring Security,我們可以將每個 角色 視為粗粒度的 GrantedAuthority,它以 String 形式表示,並以 “ROLE” 為前綴。 當直接使用 角色,例如通過表達式 hasRole(“ADMIN”),我們以粗粒度的方式限制訪問。
值得注意的是,默認的 “ROLE” 前綴是可以配置的,但如何進行配置超出了本文的範圍。
這兩個概念之間的核心區別在於我們如何使用該功能所賦予的語義。 對於框架而言,這種差異微乎其微——它基本上以完全相同的方式處理它們。
4. 作為容器的角色
現在我們已經瞭解了框架如何使用角色的概念,我們也將快速討論一種替代方案——即將角色用作權限/特權的容器。
這是一種更高層次的角色使用方式——將角色變成面向業務的概念,而不是面向實現的。
Spring Security 框架沒有提供關於如何使用該概念的指導,因此選擇完全取決於實現細節。
5. Spring Security 配置
我們可以通過限制對 /protectedbyauthority 的訪問權限,僅限擁有 READ_AUTHORITY 的用户來演示細粒度的授權需求。
我們可以通過限制對 /protectedbyrole 的訪問權限,僅限擁有 ROLE_USER 的用户來演示粗粒度的授權需求。
讓我們在我們的安全配置中配置這樣一個場景:
@Override
protected void configure(HttpSecurity http) throws Exception {
// ...
.requestMatchers("/protectedbyrole").hasRole("USER")
.requestMatchers("/protectedbyauthority").hasAuthority("READ_PRIVILEGE")
// ...
}6. 簡單數據初始化
現在我們對核心概念有了更深入的理解,接下來我們來探討在應用程序啓動時創建一些初始化數據。
這當然是一種非常簡單的方法,用於在開發過程中啓動時使用一些初步的測試用户——但這並不是在生產環境中處理數據的正確方式。
我們將監聽上下文刷新事件:
@Override
@Transactional
public void onApplicationEvent(ContextRefreshedEvent event) {
MyPrivilege readPrivilege
= createPrivilegeIfNotFound("READ_PRIVILEGE");
MyPrivilege writePrivilege
= createPrivilegeIfNotFound("WRITE_PRIVILEGE");
}實際的實現在這裏並不重要——通常取決於你所使用的持久化解決方案。主要目的是——我們正在持久化代碼中使用的權威信息。
7. UserDetailsService
我們的 UserDetailsService 實現是權限映射發生的地方。當用户經過身份驗證後,我們的 getAuthorities() 方法會填充並返回一個 UserDetails 對象:
private Collection<? extends GrantedAuthority> getAuthorities(
Collection<Role> roles) {
List<GrantedAuthority> authorities = new ArrayList<>();
for (Role role: roles) {
authorities.add(new SimpleGrantedAuthority(role.getName()));
authorities.addAll(role.getPrivileges()
.stream()
.map(p -> new SimpleGrantedAuthority(p.getName()))
.collect(Collectors.toList()));
}
return authorities;
}8. 運行和測試示例
我們可以執行 RolesAuthoritiesApplication Java 應用程序,該應用程序位於 GitHub 項目。
要查看基於角色的授權在行動中的效果,我們需要:
- 訪問 http://localhost:8082/protectedbyrole
- 使用用户名 [email protected](密碼為 “user”)進行身份驗證
- 記錄成功的授權
- 訪問 http://localhost:8082/protectedbyauthority
- 記錄未成功的授權
要查看基於權限的授權在行動中的效果,我們需要註銷應用程序,然後:
- 訪問 http://localhost:8082/protectedbyauthority
- 使用用户名 [email protected] / admin 進行身份驗證
- 記錄成功的授權
- 訪問 http://localhsot:8082/protectedbyrole
- 記錄未成功的授權
9. 結論
在本快速教程中,我們探討了 Spring Security 中 Role 和 GrantedAuthority 之間的微妙但重要的區別。