我正在使用带有ACL的Spring Security来保护我的应用程序中的文档。另一方面,我使用Hibernate Search(在lucene之上)来搜索文档。此搜索还支持分页。 (文档只是存储在数据库中的文档的元数据。)
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
QueryBuilder queryBuilder = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(Document.class).get();
Query query = queryBuilder.keyword().onFields(fieldNames.toArray(new String[0])).matching(searchQuery)
.createQuery();
FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(query, Document.class);
fullTextQuery.setFirstResult(pageable.getFirstItem());
fullTextQuery.setMaxResults(pageable.getPageSize());
现在我必须将分页与ACL结合起来。我目前唯一的想法是从FullTextQuery中删除分页,读取所有搜索结果文档,通过ACL过滤它们,然后手动进行分页。但我不喜欢这个解决方案,因为它加载所有文档,而不是只加载页面的文档。
有没有人有更好的主意?
答案 0 :(得分:4)
如果您的ACL不是太复杂,那就是您的级别数量有限,那么我建议使用Filter和Bitset来实现它。
在这里,您将找到使用过滤器进行ACL实施的其他示例 http://java.dzone.com/articles/how-implement-row-level-access
在这里,您将找到一个缓存的bitset过滤器实现,该实现已经生产了至少5年(它是我的可搜索并行文本语料库的开源Web应用程序)
查找addSourceFilter方法 http://code.google.com/p/hunglish-webapp/source/browse/trunk/src/main/java/hu/mokk/hunglish/lucene/LuceneQueryBuilder.java
答案 1 :(得分:2)
我也遇到了同样的问题,我认为没有一个简单的答案。
我认为只有两种解决方案。你所建议的那个有你所描述的性能问题,因为你必须加载文件并解析每个结果的ACL,然后自己进行分页。另一种方法是将此工作推送到索引端并在Lucene中索引ACL。这为您提供搜索性能,通过基于当前用户/组/权限/角色添加过滤器术语来隐藏用户无法看到的结果,但代价是使用ACL信息维护索引。如果您的ACL很简单,那么这可能是一个选项。如果您的ACL是分层的,那么它仍然是一个选项,但更复杂。使用ACL保持索引最新也很棘手。
您开始研究这种功能这一事实可能表明您开始扩展Database / Hibernate / Lucene解决方案。也许像Jackrabbit这样的内容库可能更合适?我想这可能是一个太过分的步骤,但值得一看,看看它是如何做到的。或者看一下SOLR,特别是这个issue,它描述了一个棘手的问题。
答案 2 :(得分:0)
Here是我的ACL实现,具有复杂的用户/组/角色分层ACL系统,使用纯Lucene查询(在Hibernate搜索之上)。