beg*_*er_ 11 spring-security querydsl spring-data
我正在尝试使用注释和spring-security为我的开源项目添加方法级安全性.我现在面临的问题是找到所有方法,特别是用于分页的方法(例如,返回页面).
使用@PostFilter可以在列表中使用(但我个人认为在应用程序而不是数据库中进行过滤不是一个好主意)但是在分页查询中完全失败.
这是有问题的,因为我有一个Entity包含List<Compound>.复合有不同的实现,用户可能只有权读取其中一个化合物.Compound使用TABLE_PER_CLASS继承.存储库实现QueryDslPredicateExecutor.
我的想法是为每个查询添加一个谓词,根据当前用户限制返回结果.然而,我有点迷失在a)用户和角色的数据模型应该如何看,以及b)如何创建谓词(一旦定义了模型,这可能很容易).或者querydsl是否已经提供基于类型的过滤(在查询类中包含的元素)?
暂时想出了以下解决方案。由于我的项目相当简单,这可能不适用于更复杂的项目。
因此任何查询方法都可以用@PreAuthorizecontains进行注释hasRole。
我的项目中的实体是个例外Container。它可以包含 的任何子类,Compound并且用户可能没有查看所有子类的权限。它们必须是过滤器。
为此,我创建了一个UserandRole实体。Compound与 具有 OneToOne 关系,Role并且该角色是该 的“read_role” Compound。User并Role具有多对多关系。
@Entity
public abstract class Compound {
//...
@OneToOne
private Role readRole;
//...
}
Run Code Online (Sandbox Code Playgroud)
我所有的存储库都实现了QueryDSLPredicateExecutor,这在这里变得非常方便。我们没有在存储库中创建自定义 findBy-methods,而是仅在服务层中创建它们并使用repositry.findAll(predicate)和repository.findOne(predicate)。谓词保存实际的用户输入+“安全过滤器”。
@PreAuthorize("hasRole('read_Container'")
public T getById(Long id) {
Predicate predicate = QCompoundContainer.compoundContainer.id.eq(id);
predicate = addSecurityFilter(predicate);
T container = getRepository().findOne(predicate);
return container;
}
private Predicate addSecurityFilter(Predicate predicate){
String userName = SecurityContextHolder.getContext().getAuthentication().getName();
predicate = QCompoundContainer.compoundContainer.compound.readRole
.users.any().username.eq(userName).and(predicate);
return predicate;
}
Run Code Online (Sandbox Code Playgroud)
注意:QCompoundContainer是 QueryDSL 生成的“元模型”类。
最后,您可能需要初始化从Container到 的QueryDSL 路径User:
@Entity
public abstract class CompoundContainer<T extends Compound>
//...
@QueryInit("readRole.users") // INITIALIZE QUERY PATH
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL,
targetEntity=Compound.class)
private T compound;
//...
}
Run Code Online (Sandbox Code Playgroud)
省略最后一步可能会导致NullPointerException.
进一步提示:CompoundService保存时自动设置角色:
if (compound.getReadRole() == null) {
Role role = roleRepository.findByRoleName("read_" + getCompoundClassSimpleName());
if (role == null) {
role = new Role("read_" + getCompoundClassSimpleName());
role = roleRepository.save(role);
}
compound.setReadRole(role);
}
compound = getRepository().save(compound)
Run Code Online (Sandbox Code Playgroud)
这有效。缺点有点明显。同样的情况Role与同一类实现的每个实例相关联Compound。
| 归档时间: |
|
| 查看次数: |
5459 次 |
| 最近记录: |