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

我想要允许的操作,如createSubUsers,或deleteAccounts,我将允许一个管理员(角色ROLE_ADMIN)。

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

我看到hasRole消费授权字符串?我的理解肯定是错的。Spring Security中的这些概念是什么?

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

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

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

或者有没有别的方法来区分这两个?或者它没有支持,我们必须自己做?


当前回答

你可以把“授权”看作是一种“许可”或“权利”。这些“权限”(通常)表示为字符串(使用getAuthority()方法)。这些字符串允许您识别权限,并让您的选民决定是否授予对某些内容的访问权。

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

Roles (as they are used in many examples) are just "permissions" with a naming convention that says that a role is a GrantedAuthority that starts with the prefix ROLE_. There's nothing more. A role is just a GrantedAuthority - a "permission" - a "right". You see a lot of places in spring security where the role with its ROLE_ prefix is handled specially as e.g. in the RoleVoter, where the ROLE_ prefix is used as a default. This allows you to provide the role names withtout the ROLE_ prefix. Prior to Spring security 4, this special handling of "roles" has not been followed very consistently and authorities and roles were often treated the same (as you e.g. can see in the implementation of the hasAuthority() method in SecurityExpressionRoot - which simply calls hasRole()). With Spring Security 4, the treatment of roles is more consistent and code that deals with "roles" (like the RoleVoter, the hasRole expression etc.) always adds the ROLE_ prefix for you. So hasAuthority('ROLE_ADMIN') means the the same as hasRole('ADMIN') because the ROLE_ prefix gets added automatically. See the spring security 3 to 4 migration guide for futher information.

但是仍然:角色只是一个具有特殊ROLE_前缀的权威。因此,在Spring安全性3中@PreAuthorize("hasRole('ROLE_XYZ')")与@PreAuthorize("hasAuthority('ROLE_XYZ')")相同,在Spring安全性4中@PreAuthorize("hasRole('ROLE_XYZ')")与@PreAuthorize("hasAuthority('ROLE_XYZ')")相同。

关于你的用例:

用户拥有角色,角色可以执行一定的操作。

您可能会在用户所属的角色和角色可以执行的操作的GrantedAuthorities中结束。角色的授予权限具有前缀ROLE_,操作具有前缀OP_。操作权限的示例可以是OP_DELETE_ACCOUNT、OP_CREATE_USER、OP_RUN_BATCH_JOBetc。角色可以是ROLE_ADMIN、ROLE_USER、ROLE_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_ADMIN, OP_DELETE_ACCOUNT等。当用户通过身份验证时,请确保从UserDetails.getAuthorities()方法返回其所有角色的所有grantedauthority和相应的操作。

例子: id为ROLE_ADMIN的管理员角色分配了OP_DELETE_ACCOUNT、OP_READ_ACCOUNT、OP_RUN_BATCH_JOB操作。 id为ROLE_USER的用户角色具有OP_READ_ACCOUNT操作。

如果一个admin日志在生成的安全上下文中具有授予的权限: Role_admin、op_delete_account、op_read_account、op_run_batch_job

如果用户记录它,它将有: ROLE_USER, OP_READ_ACCOUNT

UserDetailsService会注意收集所有角色和这些角色的所有操作,并通过返回的UserDetails实例中的getAuthorities()方法使它们可用。

其他回答

正如其他人所提到的,我认为角色是更细粒度权限的容器。

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

我可能在应用程序中有一组权限,比如创建,读取,更新,删除,然后与用户的角色相关联。

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

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

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

同样,权限在请求处理流的深处强制执行,而ROLE在到达控制器之前通过请求过滤器方式进行过滤。最佳实践规定在业务层中通过Controller实现权限强制。

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

在请求的流程流深处强制执行的权限允许使用更细粒度的权限应用程序。例如,用户可能对一级资源具有“读写”权限,但对子资源只有“读”权限。拥有ROLE_READER会限制他编辑第一级资源的权利,因为他需要写权限来编辑这个资源,但是@PreAuthorize拦截器可以阻止他编辑子资源的尝试。

Jake

你可以把“授权”看作是一种“许可”或“权利”。这些“权限”(通常)表示为字符串(使用getAuthority()方法)。这些字符串允许您识别权限,并让您的选民决定是否授予对某些内容的访问权。

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

Roles (as they are used in many examples) are just "permissions" with a naming convention that says that a role is a GrantedAuthority that starts with the prefix ROLE_. There's nothing more. A role is just a GrantedAuthority - a "permission" - a "right". You see a lot of places in spring security where the role with its ROLE_ prefix is handled specially as e.g. in the RoleVoter, where the ROLE_ prefix is used as a default. This allows you to provide the role names withtout the ROLE_ prefix. Prior to Spring security 4, this special handling of "roles" has not been followed very consistently and authorities and roles were often treated the same (as you e.g. can see in the implementation of the hasAuthority() method in SecurityExpressionRoot - which simply calls hasRole()). With Spring Security 4, the treatment of roles is more consistent and code that deals with "roles" (like the RoleVoter, the hasRole expression etc.) always adds the ROLE_ prefix for you. So hasAuthority('ROLE_ADMIN') means the the same as hasRole('ADMIN') because the ROLE_ prefix gets added automatically. See the spring security 3 to 4 migration guide for futher information.

但是仍然:角色只是一个具有特殊ROLE_前缀的权威。因此,在Spring安全性3中@PreAuthorize("hasRole('ROLE_XYZ')")与@PreAuthorize("hasAuthority('ROLE_XYZ')")相同,在Spring安全性4中@PreAuthorize("hasRole('ROLE_XYZ')")与@PreAuthorize("hasAuthority('ROLE_XYZ')")相同。

关于你的用例:

用户拥有角色,角色可以执行一定的操作。

您可能会在用户所属的角色和角色可以执行的操作的GrantedAuthorities中结束。角色的授予权限具有前缀ROLE_,操作具有前缀OP_。操作权限的示例可以是OP_DELETE_ACCOUNT、OP_CREATE_USER、OP_RUN_BATCH_JOBetc。角色可以是ROLE_ADMIN、ROLE_USER、ROLE_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_ADMIN, OP_DELETE_ACCOUNT等。当用户通过身份验证时,请确保从UserDetails.getAuthorities()方法返回其所有角色的所有grantedauthority和相应的操作。

例子: id为ROLE_ADMIN的管理员角色分配了OP_DELETE_ACCOUNT、OP_READ_ACCOUNT、OP_RUN_BATCH_JOB操作。 id为ROLE_USER的用户角色具有OP_READ_ACCOUNT操作。

如果一个admin日志在生成的安全上下文中具有授予的权限: Role_admin、op_delete_account、op_read_account、op_run_batch_job

如果用户记录它,它将有: ROLE_USER, OP_READ_ACCOUNT

UserDetailsService会注意收集所有角色和这些角色的所有操作,并通过返回的UserDetails实例中的getAuthorities()方法使它们可用。

AFAIK授予的权限和角色在春季安全是相同的。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>

不是你要找的确切的sol,但希望它有帮助

编辑:回复你的评论

角色就像spring-security中的权限。使用intercept-url和hasRole提供了一个非常细粒度的控制,对哪个角色/权限允许什么操作。

The way we handle in our application is, we define permission (i.e. role) for each operation (or rest url) for e.g. view_account, delete_account, add_account etc. Then we create logical profiles for each user like admin, guest_user, normal_user. The profiles are just logical grouping of permissions, independent of spring-security. When a new user is added, a profile is assigned to it (having all permissible permissions). Now when ever user try to perform some action, permission/role for that action is checked against user grantedAuthorities.

此外,defaultn RoleVoter使用前缀ROLE_,因此任何以ROLE_开头的权限都被认为是role,你可以通过在role voter中使用自定义RolePrefix并在spring安全中使用它来改变这种默认行为。