春季安全中的角色和授权授权之间的区别

2022-08-31 05:10:11

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

我希望这是允许的操作,例如创建子用户或删除帐户,我将允许管理员(具有角色)。ROLE_ADMIN

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

我看到正在消费字符串?我在理解上绝对是做错了。在Spring Security中,这些概念是什么?hasRoleGrantedAuthority

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

我还在查看身份验证提供程序引用的DAO中使用的接口,它使用(注意最后的授权机构):org.springframework.security.core.userdetails.UserDetailsUser

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

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


答案 1

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

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

角色(在许多示例中使用)只是具有命名约定的“权限”,该约定表明角色是以前缀开头的授权机构。仅此而已。角色只是一个授权机构 - 一个“权限” - 一个“权利”。在弹簧安全性中,您会看到很多地方,其中具有其前缀的角色被特别处理为例如在 RoleVoter 中,其中前缀用作默认值。这允许您提供角色名称而不带前缀。在Spring security 4之前,这种对“角色”的特殊处理没有得到非常一致的遵循,并且权限和角色通常被同等对待(例如,您可以在SecurityExpressionRoot中实现该方法中看到的那样 - 它只是调用 )。使用Spring Security 4,角色的处理更加一致,处理“roles”的代码(如,表达式等)始终为您添加前缀。因此,这意味着与因为前缀是自动添加的相同。有关更多信息,请参阅春季安全 3 到 4 迁移指南ROLE_ROLE_ROLE_ROLE_hasAuthority()hasRole()RoleVoterhasRoleROLE_hasAuthority('ROLE_ADMIN')hasRole('ADMIN')ROLE_

但仍然:角色只是一个具有特殊前缀的权威。所以在春季安全3中与春季安全4相同。ROLE_@PreAuthorize("hasRole('ROLE_XYZ')")@PreAuthorize("hasAuthority('ROLE_XYZ')")@PreAuthorize("hasRole('XYZ')")@PreAuthorize("hasAuthority('ROLE_XYZ')")

关于您的使用案例:

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

您可能最终会进入用户所属的角色以及角色可以执行的操作。角色 的 具有前缀,操作具有前缀 。操作权限的一个例子可以是 、 等。角色可以是 、 等。GrantedAuthoritiesGrantedAuthoritiesROLE_OP_OP_DELETE_ACCOUNTOP_CREATE_USEROP_RUN_BATCH_JOBROLE_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 表示形式,例如 等。当用户通过身份验证时,请确保从 UserDetails.getAuthorities() 方法返回其所有角色的所有授权机构和相应的操作。ROLE_ADMINOP_DELETE_ACCOUNT

示例:具有 id 的管理员角色分配了操作 、 。具有 id 的用户角色具有操作 。ROLE_ADMINOP_DELETE_ACCOUNTOP_READ_ACCOUNTOP_RUN_BATCH_JOBROLE_USEROP_READ_ACCOUNT

如果管理员在生成的安全上下文中登录时将具有授权机构:、 、 、ROLE_ADMINOP_DELETE_ACCOUNTOP_READ_ACCOUNTOP_RUN_BATCH_JOB

如果用户记录它,它将具有: ,ROLE_USEROP_READ_ACCOUNT

用户详细信息服务将负责收集所有角色和这些角色的所有操作,并通过返回的 UserDetails 实例中的 getAuthorities() 方法使它们可用。


答案 2

AFAIK GrantedAuthority和角色在春季安全中是相同的。GrantedAuthority 的 getAuthority() 字符串是角色(根据默认实现 Simple GrantAuthority)。

对于您的情况,您可以使用分层角色

<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>

不是你想要的确切溶胶,但希望它有帮助

编辑:回复您的评论

角色就像弹簧安全中的权限。将 intercept-url 与 hasRole 结合使用,可以非常精细地控制允许哪个角色/权限执行哪些操作。

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

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


推荐