Spring security 扩展SecurityExpressionRoot以在@Query中访问

Spring security 扩展SecurityExpressionRoot以在@Query中访问,spring-security,spring-data-jpa,Spring Security,Spring Data Jpa,我的RESTAPI由OAuth2保护,我希望能够编写@querys,以便只显示用户拥有的实体。实际上,使用是租户的一部分,实体由租户而不是用户拥有。租户标识符可以从JWT令牌中的作用域派生 我的想法是,我应该能够提供一个定制的SecurityExpressionRoot,它负责从作用域派生租户,并提供在@Query注释中使用的值。这是我为此制作的EvaluationContextExtension和SecurityExpressionRoot: @Component public class S

我的RESTAPI由OAuth2保护,我希望能够编写@querys,以便只显示用户拥有的实体。实际上,使用是租户的一部分,实体由租户而不是用户拥有。租户标识符可以从JWT令牌中的作用域派生

我的想法是,我应该能够提供一个定制的SecurityExpressionRoot,它负责从作用域派生租户,并提供在@Query注释中使用的值。这是我为此制作的EvaluationContextExtension和SecurityExpressionRoot:

@Component
public class SecurityEvaluationContextExtension implements EvaluationContextExtension {

    @Override
    public String getExtensionId() {
        return "security";
    }

    @Override
    public SecurityExpressionRoot getRootObject() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return new CustomSecurityExpressionRoot(authentication);
    }
    
    
    public static class CustomSecurityExpressionRoot extends SecurityExpressionRoot {
        public CustomSecurityExpressionRoot(Authentication authentication) {
            super(authentication);  
        }
        
        public String getTenant() {
            return "foo";
        }
    }

}
在存储库中,我希望能够访问租户属性并使用它构造查询:

public interface SubscriptionRepo extends CrudRepository<Subscription, Long> {
    @PreAuthorize("isFullyAuthenticated()")
    @Query("SELECT a FROM Subscription a WHERE a.owner = HOW_TO_ACCESS_THE_TENANT?")
    @Override
    Iterable<Subscription> findAll();
}
我把如何访问租户?因为这就是我现在挣扎的地方。我尝试了很多在互联网上找到的东西,比如{security.tenant}、{tenant}、{getTenant}、{security.getTenant},但似乎没有任何效果

?{security.tenant}=>SpelEvaluationException:EL1007E:在null上找不到属性或字段“tenant”

?{security.getTenant}=>SpelEvaluationException:EL1011E:方法调用:试图在空上下文对象上调用方法getTenant

?{tenant}=>SpelEvaluationException:EL1008E:在“java.lang.object[]”类型的对象上找不到属性或字段“tenant”-可能不是公共的或无效的


我不确定我是否在实现自定义安全根目录时出错,或者我的查询出错,或者它根本不起作用。有人能提供方向吗?

发现属性需要在通过EvaluationContextensionGetProperties公开的映射中明确列出。我从未在任何文档中看到过这一点,但在阅读一条错误消息时偶然发现了它。因此,带有自定义SecurityExpressionRoot的EvaluationContextExtension的工作实现如下所示:

@Component
public class EditTenantEvaluationContextExtension implements EvaluationContextExtension {

    @Override
    public Map<String, Object> getProperties() {
        Map<String, Object> properties = new HashMap<>(EvaluationContextExtension.super.getProperties());
        properties.put("tenants", getRootObject().getTenants());
        return properties;
    }

    @Override
    public String getExtensionId() {
        return "security";
    }

    @Override
    public CustomSecurityExpressionRoot getRootObject() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return new CustomSecurityExpressionRoot(authentication);
    }
    
    
    public static class CustomSecurityExpressionRoot extends SecurityExpressionRoot {
        public CustomSecurityExpressionRoot(Authentication authentication) {
            super(authentication);
        }

        public Set<String> getTenants() {
            return SecurityUtils.getTenants();
        }
    }

}
@Query("SELECT a FROM Subscription a WHERE a.owner = ?#{security.tenants}")