Spring Security中有一些概念和实现,例如GrantedAuthority
接口,用于获取权限来授权/控制访问。
我希望这是允许的操作,例如 createSubUsers 或 deleteAccounts ,我将允许 admin (带有角色{ {1}})。
我对在网上看到的教程/演示感到困惑。我尝试连接我读到的内容,但我认为我们可以互换地对待这两个。
我看到ROLE_ADMIN
使用了hasRole
字符串?我肯定在理解上做错了。这些概念在Spring Security中是什么?
如何存储用户的角色,与该角色的权限分开?
我还查看了GrantedAuthority
接口,该接口在身份验证提供程序引用的DAO中使用,该接口消耗org.springframework.security.core.userdetails.UserDetails
(注意最后一个GrantedAuthority):
User
或者还有其他方法来区分其他两个吗?或者它不受支持,我们必须自己制作?
答案 0 :(得分:306)
将GrantedAuthority视为“权限”或“权利”。那些“权限”(通常)表示为字符串(使用getAuthority()
方法)。这些字符串可让您识别权限,并让您的选民决定是否允许访问某些内容。
您可以将不同的GrantedAuthority(权限)授予用户,方法是将它们放入安全上下文中。您通常通过实现自己的UserDetailsService来执行此操作,该UserDetailsService返回返回所需GrantedAuthorities的UserDetails实现。
角色(在许多示例中使用它们)只是“权限”,其命名约定表明角色是以前缀ROLE_
开头的GrantedAuthority。没有别的了。角色只是一个GrantedAuthority - 一个“权限” - 一个“权利”。您在spring security中看到很多地方,其ROLE_
前缀的角色被特别处理为例如在RoleVoter中,ROLE_
前缀用作默认值。这允许您提供不具有ROLE_
前缀的角色名称。在Spring security 4之前,对“角色”的这种特殊处理并未得到非常一致的遵循,权威和角色通常被视为相同(正如您在{{3}中hasAuthority()
方法的实现中所看到的那样} - 只需调用hasRole()
)。使用Spring Security 4,角色处理更加一致,处理“角色”的代码(如RoleVoter
,hasRole
表达式等)总是为您添加ROLE_
前缀。因此,hasAuthority('ROLE_ADMIN')
表示与hasRole('ADMIN')
相同,因为ROLE_
前缀会自动添加。请参阅弹簧安全3至4 SecurityExpressionRoot以获取更多信息。
但是:角色只是一个带有特殊ROLE_
前缀的权威。因此,在Spring中,安全性3 @PreAuthorize("hasRole('ROLE_XYZ')")
与@PreAuthorize("hasAuthority('ROLE_XYZ')")
相同,而在Spring安全性4中@PreAuthorize("hasRole('XYZ')")
与@PreAuthorize("hasAuthority('ROLE_XYZ')")
相同。
关于您的用例:
用户具有角色和角色可以执行某些操作。
您可以在GrantedAuthorities
中查找用户所属的角色以及角色可以执行的操作。角色的GrantedAuthorities
具有前缀ROLE_
,操作具有前缀OP_
。操作权限的示例可以是OP_DELETE_ACCOUNT
,OP_CREATE_USER
,OP_RUN_BATCH_JOB
等。角色可以是ROLE_ADMIN,ROLE_USER等。
您最终可能会像在此(伪代码)示例中那样实现GrantedAuthority
:
@Entity
class Role implements GrantedAuthority {
@Id
private String id;
@OneToMany
private final List<Operation> allowedOperations = new ArrayList<>();
@Override
public String getAuthority() {
return id;
}
public Collection<GrantedAuthority> getAllowedOperations() {
return allowedOperations;
}
}
@Entity
class User {
@Id
private String id;
@OneToMany
private final List<Role> roles = new ArrayList<>();
public Collection<Role> getRoles() {
return roles;
}
}
@Entity
class Operation implements GrantedAuthority {
@Id
private String id;
@Override
public String getAuthority() {
return id;
}
}
您在数据库中创建的角色和操作的ID将是GrantedAuthority表示,例如“ROLE_ADMIN”,“OP_DELETE_ACCOUNT”等。当用户被认证,确保其所有角色的所有GrantedAuthorities和相应的操作都是从UserDetails.getAuthorities()方法返回。
实施例: ID为ROLE_ADMIN的admin角色分配了操作OP_DELETE_ACCOUNT,OP_READ_ACCOUNT,OP_RUN_BATCH_JOB。 ID为ROLE_USER的用户角色具有操作OP_READ_ACCOUNT。
如果管理员登录生成的安全上下文,则将具有GrantedAuthorities: ROLE_ADMIN,OP_DELETE_ACCOUNT,OP_READ_ACCOUNT,OP_RUN_BATCH_JOB
如果用户登录,它将具有: ROLE_USER,OP_READ_ACCOUNT
UserDetailsService将负责收集这些角色的所有角色和所有操作,并通过返回的UserDetails实例中的getAuthorities()方法使它们可用。
答案 1 :(得分:7)
AFAIK GrantedAuthority和角色在spring安全性中是相同的。 GrantedAuthority的getAuthority()字符串是角色(根据默认实现SimpleGrantedAuthority)。
对于您的情况,您可以使用分层角色
<bean id="roleVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
<constructor-arg ref="roleHierarchy" />
</bean>
<bean id="roleHierarchy"
class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<property name="hierarchy">
<value>
ROLE_ADMIN > ROLE_createSubUsers
ROLE_ADMIN > ROLE_deleteAccounts
ROLE_USER > ROLE_viewAccounts
</value>
</property>
</bean>
不是你想要的精确解决方案,但希望有所帮助
修改:回复您的评论
角色就像是spring-security中的权限。使用带有hasRole的intercept-url可以对哪个角色/权限允许的操作提供非常精细的控制。
我们在应用程序中处理的方式是,我们为每个操作(或休息URL)定义权限(即角色),例如: view_account,delete_account,add_account等。然后我们为每个用户创建逻辑配置文件,如admin,guest_user,normal_user。配置文件只是权限的逻辑分组,与spring-security无关。 添加新用户时,会为其分配配置文件(具有所有允许的权限)。现在,当用户尝试执行某些操作时,将针对用户授予的权限检查该操作的权限/角色。
此外,defaultn RoleVoter使用前缀ROLE_,因此任何以ROLE_开头的权限都被视为角色,您可以通过在角色选民中使用自定义RolePrefix并在spring security中使用它来更改此默认行为。
答案 2 :(得分:3)
理解这些概念之间关系的另一种方法是将ROLE解释为权限的容器。
权限是针对特定操作的细粒度权限,有时会与特定数据范围或上下文相关联。例如,“读取”,“写入”,“管理”可以表示对给定信息范围的各种级别的权限。
此外,在请求的处理流程中强制执行权限,而ROLE在到达Controller之前按请求过滤方式进行过滤。最佳实践规定在业务层中通过Controller实施权限实施。
另一方面,ROLES是一组权限的粗粒度表示。 ROLE_READER只有读取或查看权限,而ROLE_EDITOR同时具有读取和写入权限。角色主要用于请求处理的郊区的第一次筛选,例如 HTTP。 ... .antMatcher(...)。hasRole(ROLE_MANAGER)
在请求的流程中深入实施的权限允许对权限进行更细粒度的应用。例如,用户可能具有对第一级资源的读写权限,但只有读取到子资源。拥有一个ROLE_READER会限制他编辑第一级资源的权利,因为他需要Write权限来编辑这个资源,但是@PreAuthorize拦截器可以阻止他尝试编辑子资源。
杰克
答案 3 :(得分:3)
就像其他人提到的那样,我认为角色是获得更细化权限的容器。
尽管我发现“层次结构角色”实现缺少对这些精细权限的精细控制。
因此,我创建了一个库来管理关系,并在安全上下文中将权限作为已授予的权限注入。
我可能在应用程序中拥有一组权限,例如CREATE,READ,UPDATE,DELETE,然后与用户的Role关联。
或更具体的权限,例如READ_POST,READ_PUBLISHED_POST,CREATE_POST,PUBLISH_POST
这些权限是相对静态的,但是角色与它们之间的关系可能是动态的。
示例-
@Autowired
RolePermissionsRepository repository;
public void setup(){
String roleName = "ROLE_ADMIN";
List<String> permissions = new ArrayList<String>();
permissions.add("CREATE");
permissions.add("READ");
permissions.add("UPDATE");
permissions.add("DELETE");
repository.save(new RolePermissions(roleName, permissions));
}
您可以创建API来管理这些权限与角色之间的关系。
我不想复制/粘贴另一个答案,所以这里是指向SO的更完整说明的链接。
https://stackoverflow.com/a/60251931/1308685
要重用我的实现,我创建了一个仓库。请随时贡献!
https://github.com/savantly-net/spring-role-permissions