1. 概述
在本文中,我們將解釋 Spring Security 中 角色 和 GrantedAuthority 之間的微妙但重要的區別2. GrantedAuthority
在 Spring Security 中,我們可以將每個 GrantedAuthority 視為一個獨立的權限。 例子可能包括 READ_AUTHORITY、WRITE_PRIVILEGE,甚至 CAN_EXECUTE_AS_ROOT。 重要的是要理解的是,名稱是任意的。
當直接使用 GrantedAuthority,例如通過使用像 hasAuthority('READ_AUTHORITY') 這樣的表達式時,我們 以精細的方式限制訪問。
正如你可能已經注意到,我們可以通過使用 authority 來引用 privilege 概念。
3. 角色作為權威 (Role as Authority)
類似於 Spring Security,我們可以將每個 角色 (Role)視為粗粒度的 GrantedAuthority,它以 String 形式表示,並以 “ROLE” 為前綴。當直接使用 角色 (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. 結論
在本快速教程中,我們探討了 角色 和 GrantedAuthority 在 Spring Security 中微妙但重要的區別。