Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/spring-boot/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring QueryDsl分页筛选器(按ACL权限)_Java_Spring Boot_Spring Security_Spring Data Jpa - Fatal编程技术网

Java Spring QueryDsl分页筛选器(按ACL权限)

Java Spring QueryDsl分页筛选器(按ACL权限),java,spring-boot,spring-security,spring-data-jpa,Java,Spring Boot,Spring Security,Spring Data Jpa,让我们假设下面的Spring基于JPA的存储库支持QueryDsl @Repository public interface TeamRepository extends JpaRepository<Team, Long>, QuerydslPredicateExecutor<Team> { } 这位官员建议使用支持分页的@query编写自定义查询 我如何编写这样一个支持QueryDsl谓词、分页和基于权限的过滤的复杂查询 20年3月24日进场 在另一个例子中,我遇到

让我们假设下面的Spring基于JPA的存储库支持QueryDsl

@Repository
public interface TeamRepository extends JpaRepository<Team, Long>, QuerydslPredicateExecutor<Team> {

}
这位官员建议使用支持分页的
@query
编写自定义查询

我如何编写这样一个支持QueryDsl谓词分页和基于权限的过滤的复杂查询

20年3月24日进场

在另一个例子中,我遇到了以下基于QueryDsl的方法:不是本机查询或自定义查询,而是映射为
@Immutable
JPA实体,从而生成Q类并使用它们手动筛选权限

@Entity
@Immutable
@Table(name = "acl_object_identity")
public class AclObjectIdentity implements Serializable {

    ...
}
如何使用自定义存储库来实现这一点,扩展
QueryDslRepositorySupport
,以便查询中检查权限的部分自动附加并隐藏在自定义存储库实现中?

基于此,我开发了一种可能性,这种可能性与其说是解决方案,不如说是肮脏的解决方法

方法是向现有谓词(例如由生成的谓词)添加额外的权限筛选器。为此,ACL表必须首先映射为
@Immutable
JPA实体,以便QueryDsl可以生成相应的Q类

应附加ACL权限筛选器的此类谓词用以下注释进行标记

public Page<PostDTO> findAll(@QueryDslAclPermission(root = Post.class, permission = "READ") Predicate predicate, Pageable pageable) {

    ...
}
publicpagefindall(@QueryDslAclPermission(root=Post.class,permission=“READ”)谓词,可分页{
...
}
此注释主要保存有关构建筛选器查询所需的域类型的元信息

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.TYPE})
public @interface QueryDslAclPermission {

    Class<?> root();

    String permission();

    String identifier() default "id";
}
@Retention(RetentionPolicy.RUNTIME)
@目标({ElementType.PARAMETER,ElementType.TYPE})
public@interface QueryDslAclPermission{
类root();
字符串权限();
字符串标识符()默认为“id”;
}
实际的过滤器查询是使用以下类和Spring的

@方面
@组成部分
公共类QueryDslAclPermissionAspect{
私人许可证工厂许可证工厂;
@自动连线
公共查询SlaclPermissionAspect(PermissionFactory PermissionFactory){
this.permissionFactory=permissionFactory;
}
@大约(value=“execution(**(..,@QueryDslAclPermission(*)))
公共对象addPermissionFilter(ProceedingJoinPoint joinPoint)抛出可丢弃的{
MethodSignature=(MethodSignature)joinPoint.getSignature();
Method=signature.getMethod();
Parameter[]parameters=method.getParameters();
Object[]arguments=joinPoint.getArgs();
对于(int index=0;index
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.TYPE})
public @interface QueryDslAclPermission {

    Class<?> root();

    String permission();

    String identifier() default "id";
}
@Aspect
@Component
public class QueryDslAclPermissionAspect {

    private PermissionFactory permissionFactory;

    @Autowired
    public QueryDslAclPermissionAspect(PermissionFactory permissionFactory) {
        this.permissionFactory = permissionFactory;
    }

    @Around(value = "execution(* *(.., @QueryDslAclPermission (*), ..))")
    public Object addPermissionFilter(ProceedingJoinPoint joinPoint) throws Throwable {

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Parameter[] parameters = method.getParameters();
        Object[] arguments = joinPoint.getArgs();

        for(int index = 0; index < parameters.length; ++index) {

            if(parameters[index].getType().equals(Predicate.class) &&
                    parameters[index].isAnnotationPresent(QueryDslAclPermission.class)) {

                Predicate predicate = (Predicate) arguments[index];
                QueryDslAclPermission aclPermission = parameters[index].getAnnotation(QueryDslAclPermission.class);

                arguments[index] = addPermissionFilter(predicate, aclPermission);
            }
        }

        return joinPoint.proceed(arguments);
    }

    private Predicate addPermissionFilter(Predicate predicate, QueryDslAclPermission aclPermission) {

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if(null == authentication || !authentication.isAuthenticated()) {
            throw new IllegalStateException("Permission filtering not possible for unauthenticated principal");
        }

        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        PrincipalSid principalSid = new PrincipalSid(userDetails.getUsername());

        NumberPath<Long> idPath = new PathBuilderFactory().create(aclPermission.root())
                .getNumber(aclPermission.identifier(), Long.class);

        return idPath.in(selectPermitted(aclPermission.root(), principalSid,
                permissionFactory.buildFromName(aclPermission.permission()))).and(predicate);
    }

    private JPQLQuery<Long> selectPermitted(Class<?> targetType, PrincipalSid sid, Permission permission) {

        return selectAclEntry(targetType, sid, permission)
                .select(QAclEntry.aclEntry.aclObjectIdentity.objectIdIdentity);
    }

    private JPQLQuery<AclEntry> selectAclEntry(Class<?> targetType, PrincipalSid sid, Permission permission) {

        return new JPAQuery<AclEntry>().from(QAclEntry.aclEntry)
                .where(QAclEntry.aclEntry.aclObjectIdentity.id.in(selectAclObjectIdentity(targetType)
                        .select(QAclObjectIdentity.aclObjectIdentity.id))
                        .and(QAclEntry.aclEntry.aclSid.id.eq(selectAclSid(sid).select(QAclSid.aclSid.id)))
                        .and(QAclEntry.aclEntry.mask.eq(permission.getMask())));
    }

    private JPQLQuery<AclObjectIdentity> selectAclObjectIdentity(Class<?> targetType) {

        return new JPAQuery<AclObjectIdentity>().from(QAclObjectIdentity.aclObjectIdentity)
                .where(QAclObjectIdentity.aclObjectIdentity.objectIdClass.id.eq(selectAclClass(targetType)
                        .select(QAclClass.aclClass.id)));
    }

    private JPQLQuery<AclSid> selectAclSid(PrincipalSid sid) {

        return new JPAQuery<AclSid>().from(QAclSid.aclSid)
                .where(QAclSid.aclSid.sid.eq(sid.getPrincipal()));
    }

    private JPQLQuery<AclClass> selectAclClass(Class<?> targetType) {

        return new JPAQuery<AclClass>().from(QAclClass.aclClass)
                .where(QAclClass.aclClass.className.eq(targetType.getSimpleName()));
    }
}