温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Spring Security中的hasRole和hasAuthority有什么区别

发布时间:2021-12-07 11:52:40 来源:亿速云 阅读:999 作者:iii 栏目:大数据

这篇文章主要讲解了“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()
 

那么这两种配置有什么区别呢?

今天我们就来和大家聊一聊这个问题。

 

1.源码分析

单纯从源码上来分析,你会发现这两个东西似乎一样,先来看 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 方法时没有设置前缀。

所以我们单纯从源码角度来看,hasRolehasAuthority 这两个功能似乎一模一样,除了前缀之外就没什么区别了。

那么 Spring Security 设计者为什么要搞两个看起来一模一样的东西呢?

 

2.设计理念

从设计上来说,这是两个不同的东西。同时提供 role 和 authority 就是为了方便开发者从两个不同的维度去设计权限,所以并不冲突。

authority 描述的的是一个具体的权限,例如针对某一项数据的查询或者删除权限,它是一个 permission,例如 read_employee、delete_employee、update_employee 之类的,这些都是具体的权限,相信大家都能理解。

role 则是一个 permission 的集合,它的命名约定就是以 ROLE_ 开始,例如我们定义的 ROLE 是 ROLE_ADMINROLE_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有什么区别这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI