Spring Security中有一些概念和实现,比如获取authority来授权/控制访问的GrantedAuthority接口.

我希望这是允许的操作,比如createSubUsersdeleteAccounts,我将允许admin(角色ROLE_ADMIN).

我被我在网上看到的教程/演示搞糊涂了.我试图将我读到的东西联系起来,但我认为我们可以互换对待这两者.

我看到hasRole在消耗一根GrantedAuthority线?我在理解上肯定是做错了.Spring Security在概念上是什么?

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

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

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

或者,有没有其他方法来区分其他两个呢?或者它没有得到支持,我们必须自己做?

推荐答案

将授权视为"许可"或"权利".这些"权限"通常用字符串表示(使用getAuthority()方法).通过这些字符串,您可以识别权限,并让您的投票人决定是否授予访问权限.

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

角色(在许多示例中使用)只是"权限",其命名约定表示角色是以前缀ROLE_开头的授权.没有别的了.角色只是一种授权——一种"许可"——一种"权利".在spring security中,有很多地方会专门处理带有ROLE_前缀的角色,例如在RoleVoter中,ROLE_前缀被用作默认值.这允许您提供前缀为ROLE_的角色名称.在Spring security 4之前,对"角色"的这种特殊处理并没有得到非常一致的遵循,权限和角色通常被视为相同的(例如,您可以在SecurityExpressionRoot中实现hasAuthority()方法中看到,它只是调用hasRole()).在Spring Security 4中,角色的处理更加一致,处理"角色"的代码(如RoleVoterhasRole表达式等)总是为您添加ROLE_前缀.所以hasAuthority('ROLE_ADMIN')hasRole('ADMIN')的意思相同,因为ROLE_前缀会自动添加.更多信息请参见spring security 3至4 migration guide.

但话虽如此:角色只是一个带有特殊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_ADMINROLE_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.getAuthority()方法返回其所有角色和相应操作的所有GrantedAuthority.

例子:

如果管理员登录生成的安全上下文将具有GrantedAuthority: ROLE_ADMINOP_DELETE_ACCOUNTOP_READ_ACCOUNTOP_RUN_BATCH_JOB

如果用户登录,它将具有:

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

Java相关问答推荐

Java SSLocket查明客户端是否发送了证书

CriteriaQuery with max

转换为Biggram

scanner 如何在执行hasNextLine一次后重新读取整个文件?

为什么BasicComboBoxRenderer在文本不存在或文本为空的情况下设置两次文本?

我无法将附件发送到NetBeans之外

条件加载@ManyToMany JPA

为什么Java Annotation接口覆盖对象类中的方法

Jakarta CDI强制bean构造/注册遗留事件侦听器

具有阻塞方法的开源库是否应该为执行提供异步选项?

Log4j与jdk21兼容吗?

WebSockets和Spring Boot安全性出现错误401

如何集成语义发布和BitBucket(Java项目)

如何仅使用键/ID的一部分(组合)高效地返回映射值?

舰队运行配置Maven版本

为了安全起见,有必要复制一份 list 吗?

在线程Java中调用Interrupt()之后调用Join()

Java 21内置http客户端固定运营商线程

将基于实例编号的对象列表拆分为新的对象列表

为什么Spring要更改Java版本配置以及如何正确设置?