8

我正在设计一个对用户管理/权限有很多要求的系统,所以我决定使用 Spring Security ACL 来管理域对象级别的权限。

虽然,使用 ACL 来维护用户和实体之间的关系迫使我们依赖它在 UI 上呈现数据。

Spring Security 提供的 PostFilter 解决方案可以很好地过滤用户可以/看不到的对象,但是当我们处理具有成百上千个条目的实体时,它会出现很大的性能问题,因为我们需要从数据库中加载所有内容,然后丢弃不允许用户“看到”的对象。

此处描述了该问题 - SEC-2409 - 但该功能可用需要一些时间。因此,我试图找到一种解决方法来使用 Spring Security ACL 但避免性能问题。

我考虑过实现一些代码来检索用户可以访问的对象(在身份验证过程之后)并保持该信息可用于每个请求,以允许开发人员使用该信息来执行查询而不依赖 PostFilter .

为了实现这一点,我试图找到一种方法来检索给定主体/授予权限的权限列表,但我无法找到一种方法来使用可用的 AclService 实现来做到这一点。

示例aclService.getObjectIdentityList(<sid>,<acl_class>)

注意:该方法应使用继承结构并包括从父条目继承的所有 ObjectIdentities

有什么建议可以获取数据或解决此问题的其他方法吗?


更新

我已经找到了一种方法来检索用户可以访问的对象列表。

List<ObjectIdentity> childObjects = aclService.findChildren(objectIdentity);
Map<ObjectIdentity, Acl> result = aclService.readAclsById(childObjects, sids);

这种方法对我们有用,因为我们只有几个实体,访问由 ACL 控制,所以我们可以构造一个用户可以访问的 ObjectsIdentities 列表。

虽然,正在返回的 Map 正在返回正在传递的 ObjectIdentities 的所有 ACL,然后我需要检查用户是否有权访问正在返回的每个 ObjectIdentity。

你有一个简单的方法来做到这一点或简化所有这些逻辑吗?

4

2 回答 2

2

当前处理较大数据集的方法是更新您的查询以在您的查询中包含当前登录的用户。例如,您可以使用 Spring Security 和 Spring Data 集成来更新您的查询以引用当前用户:

@Query("select d from MyDomain d where d.owner = #{principal.name}")

显然这并不理想,因为您需要手动管理权限。一旦我们解决了SEC-2409,Spring 可以自动为您完成很多繁重的工作。

于 2015-06-17T14:57:42.593 回答
2

我遇到了这个问题,因为我需要一个解决方案来处理缺少SEC-2409。看着 JdbcAclService.findChildren() 引导我到这个

private final String FIND_OBJECTS_WITH_ACCESS = ""+
          "SELECT " +
          "    obj.object_id_identity AS obj_id, " +
          "    class.class AS class " +
          "FROM " +
          "    acl_object_identity obj, " +
          "    acl_class class, " +
          "    acl_entry entry " +
          "WHERE " +
          "    obj.object_id_class = class.id " +
          "    and entry.granting = true " +
          "    and entry.acl_object_identity = obj.id " +
          "    and entry.sid = (SELECT id FROM acl_sid WHERE sid = ?) " +
          "    and obj.object_id_class = (SELECT id FROM acl_class WHERE acl_class.class = ?) " +
          "GROUP BY " +
          "    obj.object_id_identity, " +
          "    class.class ";


public List<ObjectIdentity> getObjectsWithAccess(Class clazz, String sid) {
    Object[] args = { sid, clazz.getName() };
    List<ObjectIdentity> objects = _jdbcTemplate.query(FIND_OBJECTS_WITH_ACCESS, args, getRowMapper());
    return objects.size() == 0 ? null : objects;
}

private RowMapper<ObjectIdentity> getRowMapper() {
    return (rs, rowNum) -> {
        String javaType = rs.getString("class");
        Long identifier = rs.getLong("obj_id");
        return new ObjectIdentityImpl(javaType, identifier);
    };
}
于 2016-10-27T02:31:43.823 回答