如何通过上下文更改 Spring Security 角色?

Posted

技术标签:

【中文标题】如何通过上下文更改 Spring Security 角色?【英文标题】:How to change Spring Security roles by context? 【发布时间】:2013-12-14 16:38:48 【问题描述】:

我想知道是否可以根据所选类别设置角色。在我们的应用程序中有包含文章的类别。现在我们有一个像这样的角色层次结构:ROLE_ADMIN > ROLE_EDITOR > ROLE_USER。问题在于,根据当前选择的类别,用户可能具有不同的角色:

user1 - cat1 - ROLE_USER

user1 - cat2 - ROLE_EDITOR

类别不是静态的。可以添加新的并删除旧的。是否可以使用 Spring Security 实现这一目标?

【问题讨论】:

您能解释一下您打算如何使用“类别”吗? 类别是持有文章实体集合的实体。当用户在应用中导航时选择它。 【参考方案1】:

从您的描述来看,听起来 Spring Security 给您的 RBAC 模型是不够的。您有 2 个选项可供您使用。要么:

    您可以通过实现自己的访问决策管理器来自定义 Spring Security(有关详细信息,请参阅here)或 您转向基于属性的访问控制(也称为 ABAC,由 NIST here 解释)。在 Spring 中使用 ABAC 的方法是使用 XACML 的 Java 实现,即可扩展访问控制标记语言。 XACML 为您提供了一个外部化的、基于策略和属性的授权框架。这意味着您可以定义策略,例如具有 role=manager 的用户可以在 category=foo 中执行 action=view。您可以拥有任意数量的规则,并相应地组合/分解它们。

XACML for Java 有几个开源和供应商实现:

SunXACML 赫拉斯AF IBM Axiomatics(免责声明:我工作的供应商)

如果您想了解有关 XACML 的更多信息,我建议您查看其 wikipedia 页面以及我们的 YouTube channel,其中包含供应商中立的教程。

XACML 可能对您的用例来说太过分了,但仍然值得考虑。

【讨论】:

感谢您的赞誉。【参考方案2】:

我不知道您的“类别”是如何工作的,但您可以将“ROLE”设置为 UserDetails 对象。

UserDetails 对象具有Collection<? extends GrantedAuthority> getAuthorities(); 方法,“ROLE”是GrantedAuthority.getAuthority() 的值。

因此您可以将多个“ROLE”设置为单个会话。

你可以通过实现UserDetailsService来控制你的UserDetails对象。

【讨论】:

【参考方案3】:

此用例无法使用默认的基于角色的访问控制 (RBAC) 功能来完成,因为用户权限在运行时会根据与用户关联的某些数据动态变化。

这实际上是为访问控制列表 (ACLs) 设计的用例。

Spring security 通过添加 spring-acl jar 来支持 ACL。这是 spring 安全手册 Acl 部分的引用:

复杂的应用程序通常会发现需要定义访问权限,而不仅仅是在 Web 请求或 方法调用级别。相反,安全决策需要包括谁(身份验证), 哪里(MethodInvocation)和什么(SomeDomainObject)。换言之,授权 决策还需要考虑方法调用的实际域对象实例主体。

有关 Spring 安全 ACL 如何工作的详细信息,请参阅 spring security manual 第 16.1 节。这是关于如何使用 Spring 安全 ACL 的 tutorial。

但 Spring ACL 意味着 4 个额外的数据库表等,因此如果这是您的应用程序中唯一的情况,最好创建一个带有一些硬编码规则的自定义决策管理器。

但如果这种用例在您的应用程序中很常见,您应该考虑切换到 ACL 而不是 RBAC,希望这会有所帮助。

【讨论】:

【参考方案4】:

我想我来晚了,但这对我有用:

When a new category is selected, you can set a new Authentication object with new roles in your session(The previous authentication object gets invalidated).像这样的:

@RequestMapping(value = "/cat1")
String cat1(HttpServletRequest request) 
    reloadRolesForAuthenticatedUser("cat1")
    ....


private void reloadRolesForAuthenticatedUser(String cat) 
    Authentication auth = SecurityContextHolder.getContext().getAuthentication()
    List<String> newRoles = getRoles(auth.getPrincipal().getUsername(), cat)
    List<GrantedAuthority> authorities = getAuthorities(newRoles)
    Authentication newAuth = new UsernamePasswordAuthenticationToken(auth.getPrincipal(),auth.getCredentials(),authorities)
    SecurityContextHolder.getContext().setAuthentication(newAuth)



private List<GrantedAuthority> getAuthorities(List<String> roles) 
    List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>()
    if (!roles.isEmpty()) 
        for (String r : roles) 
            auths.add(new SimpleGrantedAuthority(r))
        
    
    return auths

【讨论】:

以上是关于如何通过上下文更改 Spring Security 角色?的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security - 更改 RedirectStrategy 的所有实例

spring security - 如何让另一个用户注销

作为管理员,如何使用 Grails Spring Security 以编程方式更改用户密码?

如何在 Spring Security 中动态切换应用程序上下文?

Spring Security:如何更改默认用户和密码?

在 Spring Boot 库的上下文中添加新的 spring-security 链过滤器的预期方法