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