290

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

我希望允许的操作,例如createSubUsersdeleteAccounts,我将允许管理员(具有角色ROLE_ADMIN)。

我在网上看到的教程/演示让我感到困惑。我试图把我读到的东西联系起来,但我认为我们可以互换地对待这两者。

我看到hasRole消耗一个GrantedAuthority字符串?我绝对在理解上做错了。Spring Security 在概念上是什么?

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

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

public User(String username, 
            String password, 
            boolean enabled, 
            boolean accountNonExpired,
            boolean credentialsNonExpired, 
            boolean accountNonLocked, 
            Collection<? extends GrantedAuthority> authorities)

或者有没有其他方法可以区分其他两者?还是不支持,我们必须自己制作?

4

4 回答 4

435

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

您可以通过将用户放入安全上下文中来向用户授予不同的 GrantedAuthority(权限)。您通常通过实现自己的 UserDetailsS​​ervice 来实现,该服务返回返回所需的 GrantedAuthorities 的 UserDetails 实现。

角色(如在许多示例中使用的那样)只是具有命名约定的“权限”,即角色是以前缀开头的 GrantedAuthority ROLE_。没有什么了。角色只是一个 GrantedAuthority - 一个“权限” - 一个“权利”。您会在 Spring Security 中看到很多地方,其中带有ROLE_前缀的角色被特别处理,例如在 RoleVoter 中,ROLE_前缀被用作默认值。这允许您提供不带ROLE_前缀的角色名称。在 Spring security 4 之前,这种对“角色”的特殊处理并没有得到非常一致的遵循,并且权限和角色通常被视为相同(例如,hasAuthority()hasRole())。使用 Spring Security 4,角色的处理更加一致,处理“角色”的代码(如RoleVoterhasRole表达式等)总是ROLE_为您添加前缀。所以意味着与自动添加前缀hasAuthority('ROLE_ADMIN')相同。有关更多信息,请参阅 spring security 3 到 4迁移指南hasRole('ADMIN')ROLE_

但仍然:角色只是具有特殊ROLE_前缀的权限。所以在 Spring security 3@PreAuthorize("hasRole('ROLE_XYZ')")中与 Spring security 4 相同@PreAuthorize("hasAuthority('ROLE_XYZ')"),在 Spring security 4@PreAuthorize("hasRole('XYZ')")中与@PreAuthorize("hasAuthority('ROLE_XYZ')").

关于您的用例:

用户具有角色并且角色可以执行某些操作。

您最终可能会GrantedAuthorities选择用户所属的角色以及角色可以执行的操作。GrantedAuthorities角色有前缀,ROLE_操作有前缀OP_。操作权限的示例可以是OP_DELETE_ACCOUNT,OP_CREATE_USEROP_RUN_BATCH_JOB。角色可以是ROLE_ADMIN,ROLE_USERROLE_OWNER

您最终可能会让您的实体GrantedAuthority在这个(伪代码)示例中实现:

@Entity
class Role implements GrantedAuthority {
    @Id
    private String id;

    @ManyToMany
    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;

    @ManyToMany
    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_ADMINOP_DELETE_ACCOUNT。当用户通过身份验证时,请确保从 UserDetails.getAuthorities() 返回其所有角色的所有 GrantedAuthorities 和相应的操作方法。

示例:具有 id 的管理员角色具有ROLE_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_USEROP_READ_ACCOUNT

UserDetailsS​​ervice 将负责收集所有角色和这些角色的所有操作,并通过返回的 UserDetails 实例中的 getAuthorities() 方法使它们可用。

于 2013-10-23T12:55:49.623 回答
12

AFAIK GrantedAuthority 和角色在 Spring Security 中是相同的。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 的拦截 url 可以非常精细地控制允许哪些操作用于哪个角色/权限。

我们在应用程序中处理的方式是,我们为每个操作(或休息 url)定义权限(即角色),例如 view_account、delete_account、add_account 等。然后我们为每个用户创建逻辑配置文件,如 admin、guest_user、normal_user。配置文件只是权限的逻辑分组,独立于 spring-security。添加新用户时,会为其分配一个配置文件(具有所有允许的权限)。现在,当用户尝试执行某些操作时,该操作的权限/角色会根据用户grantedAuthorities 检查。

此外,默认的 RoleVoter 使用前缀 ROLE_,因此任何以 ROLE_ 开头的权限都被视为角色,您可以通过在角色投票者中使用自定义 RolePrefix 并在 Spring Security 中使用它来更改此默认行为。

于 2013-10-23T09:57:47.770 回答
10

理解这些概念之间关系的另一种方法是将 ROLE 解释为 Authorities 的容器。

权限是针对特定操作的细粒度权限,有时与特定数据范围或上下文相结合。例如,读取、写入、管理可以表示对给定信息范围的不同级别的权限。

此外,权限在请求的处理流程中被强制执行,而 ROLE 在到达控制器之前通过请求过滤方式过滤。最佳实践规定在业务层中通过控制器实施权限强制执行。

另一方面,ROLES 是一组权限的粗粒度表示。ROLE_READER 将仅具有读取或查看权限,而 ROLE_EDITOR 将同时具有读取和写入权限。角色主要用于http等外围请求处理的第一次筛选。... .antMatcher(...).hasRole(ROLE_MANAGER)

在请求的流程中深入执行的权限允许更细粒度地应用权限。例如,用户可能具有对一级资源的读写权限,但仅对子资源具有读取权限。拥有 ROLE_READER 将限制他编辑第一级资源的权利,因为他需要写入权限才能编辑此资源,但 @PreAuthorize 拦截器可能会阻止他尝试编辑子资源。

杰克

于 2018-05-14T23:13:00.417 回答
5

就像其他人提到的那样,我认为角色是更精细权限的容器。

尽管我发现 Hierarchy Role 实现缺乏对这些细粒度权限的精细控制。
所以我创建了一个库来管理关系并将权限注入安全上下文中的授予权限。

我可能在应用程序中有一组权限,例如 CREATE、READ、UPDATE、DELETE,然后与用户的角色相关联。

或更具体的权限,如 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

为了重用我的实现,我创建了一个 repo。请随时贡献!
https://github.com/savantly-net/spring-role-permissions

于 2020-02-16T19:10:02.843 回答