溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Spring Security中的hasRole和hasAuthority有什么區(qū)別

發(fā)布時間:2021-12-07 11:52:40 來源:億速云 閱讀:1011 作者:iii 欄目:大數(shù)據(jù)

這篇文章主要講解了“Spring Security中的hasRole和hasAuthority有什么區(qū)別”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Spring Security中的hasRole和hasAuthority有什么區(qū)別”吧!

我相信很多小伙伴在初次接觸 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()
 

那么這兩種配置有什么區(qū)別呢?

今天我們就來和大家聊一聊這個問題。

 

1.源碼分析

單純從源碼上來分析,你會發(fā)現(xiàn)這兩個東西似乎一樣,先來看 hasAuthority。

public ExpressionInterceptUrlRegistry hasAuthority(String authority) {
 return access(ExpressionUrlAuthorizationConfigurer.hasAuthority(authority));
}
private static String hasAuthority(String authority) {
 return "hasAuthority('" + authority + "')";
}
 

最終調(diào)用了 access 方法,傳入了權(quán)限表達(dá)式 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_ 前綴,所以在數(shù)據(jù)庫中的權(quán)限字符串需要加上 ROLE_ 前綴。即數(shù)據(jù)庫中存儲的用戶角色如果是 ROLE_admin,這里就是 admin。

我們在調(diào)用 hasAuthority 方法時,如果數(shù)據(jù)是從數(shù)據(jù)庫中查詢出來的,這里的權(quán)限和數(shù)據(jù)庫中保存一致即可,可以不加 ROLE_ 前綴。即數(shù)據(jù)庫中存儲的用戶角色如果是 admin,這里就是 admin。

也就是說,使用 hasAuthority 更具有一致性,你不用考慮要不要加 ROLE_ 前綴,數(shù)據(jù)庫什么樣這里就是什么樣!而 hasRole 則不同,代碼里如果寫的是 admin,框架會自動加上 ROLE_ 前綴,所以數(shù)據(jù)庫就必須是 ROLE_admin。

看起來 hasAuthority 和 hasRole 的區(qū)別似乎僅僅在于有沒有 ROLE_ 前綴。

在最終的權(quán)限比對中,更是過分,hasAuthority 和 hasRole 居然最終都是調(diào)用了 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 在調(diào)用 hasAnyAuthorityName 方法時設(shè)置了 ROLE_ 前綴,hasAnyAuthority 在調(diào)用 hasAnyAuthorityName 方法時沒有設(shè)置前綴。

所以我們單純從源碼角度來看,hasRolehasAuthority 這兩個功能似乎一模一樣,除了前綴之外就沒什么區(qū)別了。

那么 Spring Security 設(shè)計(jì)者為什么要搞兩個看起來一模一樣的東西呢?

 

2.設(shè)計(jì)理念

從設(shè)計(jì)上來說,這是兩個不同的東西。同時提供 role 和 authority 就是為了方便開發(fā)者從兩個不同的維度去設(shè)計(jì)權(quán)限,所以并不沖突。

authority 描述的的是一個具體的權(quán)限,例如針對某一項(xiàng)數(shù)據(jù)的查詢或者刪除權(quán)限,它是一個 permission,例如 read_employee、delete_employee、update_employee 之類的,這些都是具體的權(quán)限,相信大家都能理解。

role 則是一個 permission 的集合,它的命名約定就是以 ROLE_ 開始,例如我們定義的 ROLE 是 ROLE_ADMINROLE_USER 等等。我們在 Spring Security 中的很多地方都能看到對 Role 的特殊處理,例如上篇文章我們所講的投票器和決策器中,RoleVoter 在處理 Role 時會自動添加 ROLE_ 前綴。

在項(xiàng)目中,我們可以將用戶和角色關(guān)聯(lián),角色和權(quán)限關(guān)聯(lián),權(quán)限和資源關(guān)聯(lián)。

反映到代碼上,就是下面這樣:

假設(shè)用 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 中的權(quán)限去重后再返回即可。

感謝各位的閱讀,以上就是“Spring Security中的hasRole和hasAuthority有什么區(qū)別”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對Spring Security中的hasRole和hasAuthority有什么區(qū)別這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI