Spring安全中的角色和授权的区别

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

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

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

我看到hasRole消耗一个GrantedAuthority字符串?我的理解肯定是错的。Spring Security中的这些概念是什么?

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

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

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

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

154016 次浏览

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提供了一个非常细粒度的控制,对哪个角色/权限允许什么操作。

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

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

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

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

角色(在许多示例中使用)只是带有命名约定的“权限”,即角色是以前缀ROLE_开头的GrantedAuthority。没有别的了。角色只是一个授予权限(GrantedAuthority)——一个“权限”——一个“权利”。在spring安全性中,你会看到很多地方,具有ROLE_前缀的角色被特别处理,例如在RoleVoter中,ROLE_前缀被用作默认值。这允许你提供没有ROLE_前缀的角色名。在Spring security 4之前,这种对“角色”的特殊处理并没有被非常一致地遵循,权限和角色通常被视为相同的(例如,你可以在ROLE_2中hasAuthority()方法的实现中看到——它只是调用hasRole())。在Spring Security 4中,角色的处理更加一致,处理“角色”的代码(如RoleVoterhasRole表达式等)总是为你添加ROLE_前缀。因此,hasAuthority('ROLE_ADMIN')ROLE_0的意思相同,因为ROLE_前缀是自动添加的。更多信息请参见spring security 3 to 4 ROLE_3。

但仍然:角色只是一个具有特殊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_USER, __abc6等。角色可以是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.getAuthorities()方法返回其所有角色的所有grantedauthority和相应的操作。

< p >的例子: id为ROLE_ADMIN的管理员角色被分配了操作OP_DELETE_ACCOUNTOP_READ_ACCOUNTOP_RUN_BATCH_JOB。 id为ROLE_USER的用户角色具有OP_READ_ACCOUNT.

.操作

如果一个admin日志在结果的安全上下文中将具有授予的权限: ROLE_ADMINOP_DELETE_ACCOUNTOP_READ_ACCOUNTOP_RUN_BATCH_JOB

如果用户记录它,它将有: ROLE_USER, OP_READ_ACCOUNT < / p >

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

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

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

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

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

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

杰克

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

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

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

或者更具体的权限,如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 < / p > 为了重用我的实现,我创建了一个repo。请随意投稿!< br > https://github.com/savantly-net/spring-role-permissions < / p >