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

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

user1 - cat1 - ROLE_USER

user1 - cat2 - ROLE_EDITOR

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

【问题讨论】:

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

标签: spring spring-security authorization roles


【解决方案1】:

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

  1. 您可以通过实现自己的访问决策管理器来自定义 Spring Security(有关详细信息,请参阅here)或
  2. 您转向基于属性的访问控制(也称为 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
      }
      

      【讨论】:

        猜你喜欢
        • 2019-12-18
        • 1970-01-01
        • 1970-01-01
        • 2011-07-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-14
        相关资源
        最近更新 更多