我的java spring应用程序使用ACL,它有一个服务方法来检索与给定用户对应的所有对象:
@Override
@PostFilter("hasPermission(filterObject, 'READ') or hasPermission(filterObject, 'ADMINISTRATION')")
public List<SomeClass> findAll() {
return SomeClassRepository.findAll();
}
不幸的是,当数据库中有许多对象时,此方法需要花费太多时间才能完成(超过1秒)。可能是因为它将首先从数据库中获取所有对象,然后在内存中逐个过滤它们。如何在不失去spring ACL的好处的情况下对此进行优化?
编辑:我现在提出的解决方案是为 acl_sid
及 acl_entry
并通过这些存储库获取感兴趣对象的ID。与上述方法相比,这使我的执行时间提高了10倍。新代码如下所示:
@Override
@PostFilter("hasPermission(filterObject, 'READ') or hasPermission(filterObject, 'ADMINISTRATION')")
public List<SomeClass> findAll() {
List<SomeClass> result = new ArrayList<SomeClass>();
Long userId = (Long) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
AclSid sid = aclSidRepository.findBySid(Long.toString(userId));
List<AclEntry> aclEntries = aclEntryRepository.findBySid(sid);
for (AclEntry aclEntry : aclEntries) {
AclObjectIdentity aclObjectIdentity = aclEntry.getAclObjectIdentity();
AclClass aclClass = aclObjectIdentity.getObjectIdClass();
if (aclClass.getClassName().equals("com.company.app.entity.SomeClass")) {
Optional<SomeClass> SomeClass = SomeClassRepository
.findById(aclObjectIdentity.getObjectIdIdentity());
if (SomeClass.isPresent()) {
result.add(SomeClass.get());
}
}
}
return result;
}
1条答案
按热度按时间jmo0nnb31#
由于spring过滤内存中的信息,性能将取决于结果的实际数量:如果有大量结果,恐怕在过滤信息之前只缓存存储库结果可能是一个合适的解决方案。
为了解决这个问题,您可以在数据库级别过滤结果。我想到了两种方法:
任用
Specification
s、 并根据spring security公开的主体信息在数据库级别过滤结果SecurityContext
包括必要的过滤器Predicates
以限制返回的信息。或者,如果您使用的是hibernate,请使用实体过滤器,根据spring security公开的主体信息,再次应用必要的数据限制。请参阅此相关so问题,该问题提供了有关解决方案的详细信息。
请考虑,例如,Spring Data 的使用情况
Specification
S而不是
SomeClass
,让我们假设我们正在处理银行账户。让我们创建相应的实体:以及相应的存储库:
为了根据执行查询的用户筛选信息,我们可以定义一个实用工具方法,该方法基于用户权限返回
List
属于Predicates
我们可以在以后添加到我们在某个特定应用程序中使用的Specification
过滤银行账户时:哪里
hasAuthority
可能看起来像:现在,在构建应用程序时使用这些方法
Specification
S例如,考虑:请原谅我的简单用例,但我希望你能理解。
@osamaabdulrehman在他的评论中提出的解决方案看起来也很有趣,尽管老实说我从未测试过。