Spring Security 中的授权与角色
上次更新:2024 年 1 月 8 日
1. 概述
在这篇简短的文章中,我们将解释 Spring Security 中 Role 和 GrantedAuthority 之间微妙但重要的区别。有关角色和授权的更详细信息,请参阅 此处 的文章。
更多阅读
2. GrantedAuthority
在 Spring Security 中,我们可以 将每个 GrantedAuthority 视为一个单独的权限。 示例可能包括 READ_AUTHORITY、WRITE_PRIVILEGE,甚至 CAN_EXECUTE_AS_ROOT。 重要的一点是 名称是任意的。
在使用 GrantedAuthority 直接进行操作时,例如通过使用类似于 hasAuthority(‘READ_AUTHORITY’) 的表达式,我们正在 以细粒度的方式限制访问。
正如您可能猜到的那样,我们也可以使用 privilege 来指代 authority 的概念。
3. 角色作为授权
同样,在 Spring Security 中,我们可以 将每个 Role 视为一个粗粒度的 GrantedAuthority,它表示为一个 String 并以“ROLE”作为前缀。 当直接使用 Role 时,例如通过使用类似于 hasRole(“ADMIN”) 的表达式,我们正在以粗粒度的方式限制访问。
值得注意的是,默认的“ROLE”前缀是可配置的,但解释如何操作超出了本文的范围。
这两个概念的核心区别在于我们附加到如何使用该功能的语义。 对于框架而言,区别很小——基本上以相同的方式处理它们。
4. 角色作为容器
现在我们已经了解了框架如何使用 role 概念,让我们快速讨论另一种方法——**将角色用作权限/特权的容器**。
这是一种更高层次的角色方法——使它们成为更面向业务的概念,而不是以实现为中心的概念。
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 项目。
要查看基于角色的授权效果,我们需要
- 访问 https://:8082/protectedbyrole
- 以 [email protected](密码为 “user”)身份进行身份验证
- 注意授权成功
- 访问 https://:8082/protectedbyauthority
- 注意授权失败
要查看基于权限的授权效果,我们需要退出应用程序,然后
- 访问 https://:8082/protectedbyauthority
- 以 [email protected] / admin 身份进行身份验证
- 注意授权成功
- 访问 http://localhsot:8082/protectedbyrole
- 注意授权失败
9. 结论
在本快速教程中,我们探讨了 Spring Security 中Role 和 GrantedAuthority 之间细微但重要的区别。















