【问题标题】:Custom PermissionEvaluator for authorizing resource access for each REST Resource用于授权每个 REST 资源的资源访问的自定义 PermissionEvaluator
【发布时间】:2016-04-10 02:11:35
【问题描述】:

我已经实现了一个带有一些复杂授权要求的 REST 应用程序。

总结一下

我的客户购买了一个名为 Collector 的代理设备,它可以集中他们的家庭自动化控制。我的客户还购买了多个家庭自动化设备(我们称之为 HADevices),这些设备通过收集器将他们的指标报告给我的 REST 应用程序。

具有角色 ROLE_ADMIN 的管理员(我的客户服务代表)应该能够查看来自任何收集器或 HADevice 的任何数据。具有 ROLE_USER 角色的客户应该只能查看有关收集器或他/她拥有的 HADevice 的数据。

具有角色 ROLE_COLLECTOR 的收集器是唯一有权插入数据的角色,即在我的 REST 服务中创建或更新资源。我们将此 URL 称为 /deviceMetrics (POST)。收集器可以插入与客户关联的任何 HADevice 的指标。 HADevices 没有角色,也不与我的 REST 应用程序交互。收集器只能将记录插入与收集器具有相同客户的 HADevices。

我使用 spring security 4.0 进行身份验证,使用 @Secured 注解进行授权。但是,我发现我的代码中充斥着重复的权限验证,这些验证占据了我的大部分逻辑。基本的插入和检索非常简单。

我想使用 PermissionEvaluator 来集中访问控制。我必须保护以下网址

  • GET /collectors/{id}/deviceMetrics - 我从 委托人并验证我春天中 id={id} 的收集器 数据存储库属于委托人,如果不是,我发送 403
  • GET/hadevices/{id}/deviceMetrics - 我从 委托人并验证我的 spring 数据中 id={id} 的 HADevice 存储库属于委托人,如果不是,我发送 403。
  • POST /collectors/{id}/deviceMetrics - 我检索收集器 uniqueId 从 Principal 获取并确保 Collector 的 id 与 网址中的 {id}
  • POST /hadevice/{id}/deviceMetrics - 我检索 来自 Principal 和关联客户的收集器 uniqueId。一世 还使用 id={id} 拉取与 HADevice 关联的客户和 比较两者。如果它们不相等,我会发送 403。

我的应用程序对每个 REST 资源都有如此复杂的授权要求,我想使用自定义的 org.springframework.security.access.PermissionEvaluator,特别是通过实现以下方法。

boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission)

我打算结合使用 targetType 和 request.getUrl() 来为每个 url 和资源获取一个专门的 Evaluator。 有没有更好的方法来做到这一点?

【问题讨论】:

    标签: java spring rest spring-security acl


    【解决方案1】:

    您的问题非常广泛,但我认为在大多数情况下您可以使用非常简单的逻辑。

    GET /collectors/{id}/deviceMetrics

    鉴于您有一个具有合适属性的 DeviceMetrics 类,您可以使用以下内容注释您的数据存储库:

    @PostAuthorize("hasRole('ROLE_ADMIN') or (hasRole('ROLE_USER') and returnObject.collector.owner = authentication.name)")
    public DeviceMetrics getDeviceMetrics(long deviceId);
    

    (假设DeviceMetrics 类有一个属性collector 有一个属性owner 是用户名。)

    这根本不需要 PermissionEvaluator。也许您需要一个用于更复杂的情况:

    POST /collectors/{id}/deviceMetrics

    @PreAuthorize("hasRole('ROLE_COLLECTOR') and hasPermission(#collectorId, 'com.example.Collector', 'WRITE')")
    public void saveDeviceMetrics(long collectorId, DeviceMetrics deviceMetrics);
    

    您只需要一个 PermissionEvaluator,因为您获得了作为方法参数所需的所有信息。

    【讨论】:

    • 我的代码最终被一些细微不同的注释所淹没,其中大部分我需要重用。但是我想出了一种方法来继承 Permission 对象并使用 HashMap 并选择一个适当的 Permission 类来保存我需要的所有复杂授权逻辑。
    • 另一个痛点是我必须编写集成测试来测试每种方法的授权,这需要很长时间,而且 SpEL 中的任何错误都只会在运行时被捕获。
    • Rob Winch 在他的 Spring Security 3.0 演示中说他更喜欢 PermissionEvaluators,因为它们可以更好地进行单元测试,并且可以在任何地方复制 SPeL。此外,SPeL 错误仅在运行时出现,所以我想获得一个自定义 PermissionEvaluator。感谢您的回复,因为您的回答让我的想法略有不同,我找到了一个不包括在我的代码中散布 SPeL 的解决方案。
    • @horatius 好吧,你可以在测试中覆盖 SpEL 表达式,尤其是 Spring Security 的第 4 版改进了测试功能。
    【解决方案2】:

    对于那些想知道我的解决方案是什么样子的人,我借用了 this 示例。

    它很旧,它基于我不是特别喜欢的 xml 配置。但想法是创建一个 Map 并初始化自定义 PermissionValidator 并将授权逻辑存储在 Permission 接口实现中。

    最大的痛点是注入一个自动装配的元组 HashMap,但这是一个有经验的 Spring 用户可以弄清楚的实现细节。

    【讨论】:

      猜你喜欢
      • 2018-10-11
      • 1970-01-01
      • 2023-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-30
      • 2013-09-22
      相关资源
      最近更新 更多