Spring Security中角色与GrantedAuthority的区别

时间:2013-10-22 18:17:50

标签: java spring spring-security

Spring Security中有一些概念和实现,例如GrantedAuthority接口,用于获取权限来授权/控制访问。

我希望这是允许的操作,例如 createSubUsers deleteAccounts ,我将允许 admin (带有角色{ {1}})。

我对在网上看到的教程/演示感到困惑。我尝试连接我读到的内容,但我认为我们可以互换地对待这两个。

我看到ROLE_ADMIN使用了hasRole字符串?我肯定在理解上做错了。这些概念在Spring Security中是什么?

如何存储用户的角色,与该角色的权限分开?

我还查看了GrantedAuthority接口,该接口在身份验证提供程序引用的DAO中使用,该接口消耗org.springframework.security.core.userdetails.UserDetails(注意最后一个GrantedAuthority):

User

或者还有其他方法来区分其他两个吗?或者它不受支持,我们必须自己制作?

4 个答案:

答案 0 :(得分:306)

将GrantedAuthority视为“权限”或“权利”。那些“权限”(通常)表示为字符串(使用getAuthority()方法)。这些字符串可让您识别权限,并让您的选民决定是否允许访问某些内容。

您可以将不同的GrantedAuthority(权限)授予用户,方法是将它们放入安全上下文中。您通常通过实现自己的UserDetailsS​​ervice来执行此操作,该UserDetailsS​​ervice返回返回所需GrantedAuthorities的UserDetails实现。

角色(在许多示例中使用它们)只是“权限”,其命名约定表明角色是以前缀ROLE_开头的GrantedAuthority。没有别的了。角色只是一个GrantedAuthority - 一个“权限” - 一个“权利”。您在spring security中看到很多地方,其ROLE_前缀的角色被特别处理为例如在RoleVoter中,ROLE_前缀用作默认值。这允许您提供不具有ROLE_前缀的角色名称。在Spring security 4之前,对“角色”的这种特殊处理并未得到非常一致的遵循,权威和角色通常被视为相同(正如您在{{3}中hasAuthority()方法的实现中所看到的那样} - 只需调用hasRole())。使用Spring Security 4,角色处理更加一致,处理“角色”的代码(如RoleVoterhasRole表达式等)总是为您添加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_ACCOUNTOP_CREATE_USEROP_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

UserDetailsS​​ervice将负责收集这些角色的所有角色和所有操作,并通过返回的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