Spring security Spring数据JPA和Spring安全性:在数据库级别进行过滤(特别是分页)
我正试图使用注释和spring安全性将方法级安全性添加到我的开源项目中。我现在面临的问题是findAll方法,尤其是分页方法(例如返回页面) 使用@PostFilter可以在列表上工作(但我个人认为在应用程序而不是数据库中进行过滤不是一个好主意),但在分页查询上完全失败 这是有问题的,因为我有一个包含Spring security Spring数据JPA和Spring安全性:在数据库级别进行过滤(特别是分页),spring-security,spring-data,querydsl,Spring Security,Spring Data,Querydsl,我正试图使用注释和spring安全性将方法级安全性添加到我的开源项目中。我现在面临的问题是findAll方法,尤其是分页方法(例如返回页面) 使用@PostFilter可以在列表上工作(但我个人认为在应用程序而不是数据库中进行过滤不是一个好主意),但在分页查询上完全失败 这是有问题的,因为我有一个包含列表的实体。化合物有不同的实现,用户可能只有读取其中一种化合物的权限。复合使用每个类的表
列表的实体。化合物有不同的实现,用户可能只有读取其中一种化合物的权限。复合使用每个类的表
继承。存储库实现了querydsldpredicateexecutor
我的想法是为每个查询添加一个谓词,根据当前用户限制返回结果。然而,我对a)用户和角色的数据模型应该是什么样子以及b)然后如何创建谓词(一旦定义了模型,这可能很容易)有点迷茫。或者querydsl是否已经提供了基于类型的过滤(在查询的类中包含的元素上)?目前没有这种支持,但我们已经在路线图上提供了它。您可能希望了解总体进展情况。目前,有人提出了以下解决方案。由于我的项目相当简单,这可能不适用于更复杂的项目
用户可以读取某个类的所有实体,也可以不读取任何实体
因此,任何查询方法都可以用@PreAuthorize
注释,其中包含hasRole
例外情况是我的项目中的容器
实体。它可以包含component
的任何子类,用户可能没有查看所有子类的权限。它们必须是过滤器
为此,我创建了一个用户
和角色
实体<代码>化合物
与角色
有一个一键关系,该角色是该化合物
的“读取角色”<代码>用户和角色
有很多关系
@实体
公共抽象类复合{
//...
@奥内托内
私人角色;
//...
}
我所有的存储库都实现了querydsldpredicateexecutor
,这在这里非常有用。我们不在存储库中创建自定义findBy方法,而是仅在服务层中创建它们,并使用repositry.findAll(谓词)
和repository.findOne(谓词)
。谓词保存实际用户输入+安全过滤器
@PreAuthorize(“hasRole('read_Container'))
公共T getById(长id){
谓词=QCompoundContainer.compoundContainer.id.eq(id);
谓词=addSecurityFilter(谓词);
T container=getRepository().findOne(谓词);
返回容器;
}
专用谓词addSecurityFilter(谓词谓词){
字符串用户名=SecurityContextHolder.getContext().getAuthentication().getName();
谓词=QCompoundContainer.compoundContainer.component.readRole
.users.any().username.eq(用户名)和(谓词);
返回谓词;
}
注意:QCompoundContainer
是QueryDSL生成的“元模型”类
最后,您可能需要初始化从Container
到User
的QueryDSL路径:
@实体
公共抽象类复合容器
//...
@QueryInit(“readRole.users”)//初始化查询路径
@manytone(fetch=FetchType.EAGER,cascade=CascadeType.ALL,
targetEntity=composite.class)
私人T型化合物;
//...
}
忽略这最后一步可能会导致NullPointerException
进一步提示:CompoundService
在保存时自动设置角色:
if(component.getReadRole()==null){
Role-Role=roleRepository.findByRoleName(“读取”+getCompoundClassSimpleName());
如果(角色==null){
role=新角色(“读取”+getCompoundClassSimpleName());
role=roleRepository.save(角色);
}
复合。setReadRole(角色);
}
复合=getRepository()。保存(复合)
这是可行的。缺点有点明显。相同的
角色
与相同的复合
类实现的每个实例相关联。有关问题,请参阅我的意思部分,以便我可以调整查询以考虑到当前用户的角色,例如,从给定实体到r必须存在关系然后查看ACL和相应的数据库模式