我在我的存储库中有这个hibernate过滤器:
@Entity
@Audited
@DiscriminatorValue(value = "GROUP")
@FilterDef(name = "groupACL", parameters = @ParamDef(name = "userId", type = "long"))
@Filters({
@Filter(name = "groupACL", condition = "app_group_id IN (SELECT DISTINCT APP_GROUP_ID FROM APP_GROUP START WITH APP_GROUP_ID IN (SELECT UG.APP_GROUP_ID FROM USER_GROUP UG JOIN APP_USER AU ON AU.APP_USER_ID = UG.APP_USER_ID WHERE USER_ID=:userId) CONNECT BY PARENT_APP_GROUP_ID = PRIOR APP_GROUP_ID)", deduceAliasInjectionPoints = false) })
public class Group extends AbstractGroup {
使用Spring AOP使用以下类触发:
@Component
@Aspect
public class ACLFilterAspect {
private static final String GROUP_ACL = "groupACL";
@Autowired
private EntityManager em;
@Before("execution(* com.trendshift.kyn.pug.data.GroupRepository.*(..))")
public void forceFilter() {
Session hibernateSession = em.unwrap(Session.class);
....
hibernateSession.enableFilter(GROUP_ACL).setParameter("userId", userId);
}
}
}
我终于有了以下服务:
@Service
@Transactional(propagation = Propagation.REQUIRED)
public class GroupServiceImpl implements GroupService {
@Autowired
GroupRepository groupRepository;
@Override
public Group findGroupById(long id) {
Group group = groupRepository.findById(id);
return group;
}
}
和这些存储库:
@RepositoryRestResource(exported = false)
public interface AbstractGroupRepository<T extends AbstractGroup>
extends JpaRepository<T, Long>, QueryDslPredicateExecutor<T> {
List<T> findByNameIgnoreCase(String name);
List<T> findByNameAndTypeOrderByNameAsc(String name, String type);
List<T> findByIdOrderByNameAsc(Long id);
AbstractGroup findById(Long id);
}
public interface GroupRepository
extends AbstractGroupRepository<Group>, GroupRepositoryExtras {
List<Group> findByNameAndCustomerId(String name, Long customerId);
Iterable<Group> findByCustomerIdAndTypeIn(Long id, List<String> types);
Group findById(long id);
}
问题在于,当我使用groupRepository。 findById(id)时,过滤器已正确应用。
如果我使用CRUD核心查询groupRepository。 findOne(id),即使在处理了Aspect hibernateSession.enableFilter(GROUP_ACL).setParameter(“userId”,userId)之后,也不会应用过滤器; 即使Java启用了过滤器,日志文件也不会在hibernate查询中显示任何过滤器的痕迹。
问题似乎只与.findOne有关。 findAll工作正常。
Hibernate文档中是否有一些内容表明您无法将过滤器应用于findOne方法?
答案 0 :(得分:2)
我使用过滤器来限制用户基于实体属性访问某些信息。这就是为什么我甚至连findOne也要尊重过滤器的原因。
这是我发现解决此“问题”的最漂亮方法。
ClassPool pool = ClassPool.getDefault();
try {
CtClass cl = pool.get("org.hibernate.loader.plan.exec.internal.EntityLoadQueryDetails");
CtMethod me = cl.getDeclaredMethod("applyRootReturnFilterRestrictions");
String s = "{final org.hibernate.persister.entity.Queryable rootQueryable = (org.hibernate.persister.entity.Queryable) getRootEntityReturn().getEntityPersister();" +
"$1.appendRestrictions(" +
"rootQueryable.filterFragment(" +
"entityReferenceAliases.getTableAlias()," +
"getQueryBuildingParameters().getQueryInfluencers().getEnabledFilters()" +
"));}";
me.setBody(s);
cl.toClass();
} catch (Exception e) {}
答案 1 :(得分:1)
我最终收听了对CRUDRepository类的任何访问权限。不确定这是否是最好的方法,但这解决了我的问题。
@Component
@Aspect
public class ACLFilterAspect {
private static final String GROUP_ACL = "groupACL";
@Autowired
private EntityManager em;
@Before("||execution(* *(..)) && this(com.trendshift.kyn.pug.data.GroupRepository)"
+ "||execution(* *(..)) && this(org.springframework.data.repository.CrudRepository)")
答案 2 :(得分:1)
只需覆盖findById
并改用getById
@Repository
public interface CustomerRepository extends JpaRepository<Customer, Long>, JpaSpecificationExecutor<Customer>, SupportedRepositoryOperation<Customer> {
default Optional<Customer> findById(Long aLong) {
throw new OperationFindByIdNotAllowedException();
}
Optional<Customer> getById(Long id);
}
答案 3 :(得分:0)
要回答实际问题:
Hibernate文档中是否有某些内容表明您无法将过滤器应用于findOne方法?
是的,有。来自the Hibernate docs
过滤器适用于实体查询,但不适用于直接提取。 因此,在以下示例中,从持久性上下文中获取实体时不考虑过滤器。
entityManager
.unwrap( Session.class )
.enableFilter( "activeAccount" )
.setParameter( "active", true);
Account account = entityManager.find( Account.class, 2L );
assertFalse( account.isActive() );
在Spring中,例如SimpleJpaRepository.java的实现使用em.find under the hood。因此,该请求未过滤。 但是,如果您以某种方式(例如通过使用投影或编写自定义查询)覆盖实现,从而生成查询,则会过滤请求 。 这种行为可能会造成混乱。