Spring security Spring数据JPA和Spring安全性:在数据库级别进行过滤(特别是分页)

Spring security Spring数据JPA和Spring安全性:在数据库级别进行过滤(特别是分页),spring-security,spring-data,querydsl,Spring Security,Spring Data,Querydsl,我正试图使用注释和spring安全性将方法级安全性添加到我的开源项目中。我现在面临的问题是findAll方法,尤其是分页方法(例如返回页面) 使用@PostFilter可以在列表上工作(但我个人认为在应用程序而不是数据库中进行过滤不是一个好主意),但在分页查询上完全失败 这是有问题的,因为我有一个包含列表的实体。化合物有不同的实现,用户可能只有读取其中一种化合物的权限。复合使用每个类的表

我正试图使用注释和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和相应的数据库模式