目前没有这样的支持,但我们在路线图上有这样的支持。你可能想跟随 DATACMNS-293 一般进展。
暂时想出了以下解决方案。由于我的项目相当简单,这可能不适用于更复杂的项目。
因此任何查询方法都可以用注释 @PreAuthorize 含 hasRole 。
@PreAuthorize
hasRole
例外是 Container 我项目中的实体。它可以包含任何子类 Compound 并且用户可能没有权限查看所有这些权限。他们必须过滤。
Container
Compound
为此我创造了一个 User 和 Role 实体。 Compound 有一个OneToOne关系 Role 而那个角色就是那个“read_role” Compound 。 User 和 Role 有一个ManyToMany关系。
User
Role
@Entity public abstract class Compound { //... @OneToOne private Role readRole; //... }
我所有的存储库都实现了 QueryDSLPredicateExecutor 而这在这里变得非常有用。我们不是在存储库中创建自定义findBy方法,而是仅在服务层中创建它们并使用 repositry.findAll(predicate) 和 repository.findOne(predicate) 。谓词保存实际用户输入+“安全过滤器”。
QueryDSLPredicateExecutor
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; }
注意: QCompoundContainer 是QueryDSL生成的“元模型”类。
QCompoundContainer
最后,您可能需要初始化QueryDSL路径 Container 至 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; //... }
省略最后一步可以导致一个 NullPointerException 。
NullPointerException
进一步提示: CompoundService 自动设置保存角色:
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)
这有效。缺点是有点明显。相同 Role 与每个相同的实例相关联 Compound 类实现。