您好,登錄后才能下訂單哦!
這篇文章主要講解了“Spring Security中的hasRole和hasAuthority有什么區別”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Spring Security中的hasRole和hasAuthority有什么區別”吧!
我相信很多小伙伴在初次接觸 Spring Security 時,一定會被這個問題所困擾,例如如下兩段配置:
http.authorizeRequests()
.antMatchers("/admin/**").hasAuthority("admin")
.antMatchers("/user/**").hasAuthority("user")
.anyRequest().authenticated()
以及
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/user/**").hasRole("user")
.anyRequest().authenticated()
那么這兩種配置有什么區別呢?
今天我們就來和大家聊一聊這個問題。
單純從源碼上來分析,你會發現這兩個東西似乎一樣,先來看 hasAuthority。
public ExpressionInterceptUrlRegistry hasAuthority(String authority) {
return access(ExpressionUrlAuthorizationConfigurer.hasAuthority(authority));
}
private static String hasAuthority(String authority) {
return "hasAuthority('" + authority + "')";
}
最終調用了 access 方法,傳入了權限表達式 hasAuthority('xxx')。
再看 hasRole:
public ExpressionInterceptUrlRegistry hasRole(String role) {
return access(ExpressionUrlAuthorizationConfigurer.hasRole(role));
}
private static String hasRole(String role) {
Assert.notNull(role, "role cannot be null");
if (role.startsWith("ROLE_")) {
throw new IllegalArgumentException(
"role should not start with 'ROLE_' since it is automatically inserted. Got '"
+ role + "'");
}
return "hasRole('ROLE_" + role + "')";
}
可以看到,hasRole 的處理邏輯和 hasAuthority 似乎一模一樣,不同的是,hasRole 這里會自動給傳入的字符串加上 ROLE_
前綴,所以在數據庫中的權限字符串需要加上 ROLE_
前綴。即數據庫中存儲的用戶角色如果是 ROLE_admin
,這里就是 admin。
我們在調用 hasAuthority
方法時,如果數據是從數據庫中查詢出來的,這里的權限和數據庫中保存一致即可,可以不加 ROLE_
前綴。即數據庫中存儲的用戶角色如果是 admin,這里就是 admin。
也就是說,使用 hasAuthority
更具有一致性,你不用考慮要不要加 ROLE_
前綴,數據庫什么樣這里就是什么樣!而 hasRole
則不同,代碼里如果寫的是 admin
,框架會自動加上 ROLE_
前綴,所以數據庫就必須是 ROLE_admin
。
看起來 hasAuthority 和 hasRole 的區別似乎僅僅在于有沒有 ROLE_
前綴。
在最終的權限比對中,更是過分,hasAuthority 和 hasRole 居然最終都是調用了 hasAnyAuthorityName 方法(SecurityExpressionRoot 類):
public final boolean hasAuthority(String authority) {
return hasAnyAuthority(authority);
}
public final boolean hasAnyAuthority(String... authorities) {
return hasAnyAuthorityName(null, authorities);
}
public final boolean hasRole(String role) {
return hasAnyRole(role);
}
public final boolean hasAnyRole(String... roles) {
return hasAnyAuthorityName(defaultRolePrefix, 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;
}
hasAnyRole 在調用 hasAnyAuthorityName 方法時設置了 ROLE_
前綴,hasAnyAuthority 在調用 hasAnyAuthorityName 方法時沒有設置前綴。
所以我們單純從源碼角度來看,hasRole
和 hasAuthority
這兩個功能似乎一模一樣,除了前綴之外就沒什么區別了。
那么 Spring Security 設計者為什么要搞兩個看起來一模一樣的東西呢?
從設計上來說,這是兩個不同的東西。同時提供 role 和 authority 就是為了方便開發者從兩個不同的維度去設計權限,所以并不沖突。
authority 描述的的是一個具體的權限,例如針對某一項數據的查詢或者刪除權限,它是一個 permission,例如 read_employee、delete_employee、update_employee 之類的,這些都是具體的權限,相信大家都能理解。
role 則是一個 permission 的集合,它的命名約定就是以 ROLE_
開始,例如我們定義的 ROLE 是 ROLE_ADMIN
、ROLE_USER
等等。我們在 Spring Security 中的很多地方都能看到對 Role 的特殊處理,例如上篇文章我們所講的投票器和決策器中,RoleVoter 在處理 Role 時會自動添加 ROLE_
前綴。
在項目中,我們可以將用戶和角色關聯,角色和權限關聯,權限和資源關聯。
反映到代碼上,就是下面這樣:
假設用 Spring Security 提供的 SimpleGrantedAuthority 的代表 authority,然后我們自定義一個 Role,如下:
public class Role implements GrantedAuthority {
private String name;
private List<SimpleGrantedAuthority> allowedOperations = new ArrayList<>();
@Override
public String getAuthority() {
return name;
}
public List<SimpleGrantedAuthority> getAllowedOperations() {
return allowedOperations;
}
public void setAllowedOperations(List<SimpleGrantedAuthority> allowedOperations) {
this.allowedOperations = allowedOperations;
}
}
一個 Role 就是某些 authority 的集合,然后在 User 中定義 roles 集合。
public class User implements UserDetails {
private List<Role> roles = new ArrayList<>();
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (Role role : roles) {
authorities.addAll(role.getAllowedOperations());
}
return authorities.stream().distinct().collect(Collectors.toList());
}
}
在 getAuthorities 方法中,加載 roles 中的權限去重后再返回即可。
感謝各位的閱讀,以上就是“Spring Security中的hasRole和hasAuthority有什么區別”的內容了,經過本文的學習后,相信大家對Spring Security中的hasRole和hasAuthority有什么區別這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。