Spring Data Rest中的存储库访问控制基于用户原理

我正在尝试实现细粒度访问控制,同时仍然利用Spring数据rest。

我正在努力保护CrudRepository以便用户只能修改或插入属于他们的数据。 我正在使用@PreAuthorize / @PostAuthorize@PreFilter / @PostFilter将访问锁定到当前主体。

到目前为止我的存储库看起来像这样

 public interface MyRepository extends CrudRepository { @PreAuthorize("#entity.userId == principal.id") @Override  S save(S entity); @PreFilter("filterObject.userId === principal.id") @Override  Iterable save(Iterable entities); @PostAuthorize("returnObject.userId == principal.id") @Override MyObject findOne(Integer integer); @PostFilter("filterObject.userId == principal.id") @Override Iterable findAll(); } 

虽然这有点单调乏味,但它似乎完成了我所追求的目标。 (如果有人知道更好的方式,请随时告诉我!)

我遇到问题的地方是delete()count()exists()

  @Override long count(); @Override void delete(Integer integer); @Override void delete(MyObject entity); @Override void deleteAll(); @Override boolean exists(Integer integer); 

这些方法要么采用Integer ID参数,要么根本不采用。 看起来我必须首先选择具有输入ID的实体,然后执行身份validation检查。

存储库中是否可以使用此类授权?

谢谢

编辑:

感谢ksokol,这似乎现在正在运作。

我在@Configuration类中添加了一个新bean

 @Bean public EvaluationContextExtension securityExtension() { return new SecurityEvaluationContextExtensionImpl(); } 

此bean扩展了EvaluationContextExtensionSupport并覆盖了getRootObject以返回保存我的自定义主体的SecurityExpressionRoot

 public class SecurityEvaluationContextExtensionImpl extends EvaluationContextExtensionSupport { @Override public String getExtensionId() { return "security"; } @Override public Object getRootObject() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); return new SecurityExpressionRoot(authentication){}; } } 

从Spring Security 4.0开始,您可以访问Spring Data JPA查询中的安全上下文。

SecurityEvaluationContextExtension bean添加到bean上下文中:

 @Bean public SecurityEvaluationContextExtension securityEvaluationContextExtension() { return new SecurityEvaluationContextExtension(); } 

现在,您应该能够在Spring Data查询中访问Principal

 @Query("select count(m) from MyObject as m where m.user.id = ?#{ principal?.id }") @Override long count(); @Modifying @Query("delete from MyObject as m where m.id = ?1 and m.user.id = ?#{ principal?.id }") @Override void delete(Integer integer); @Modifying @Query("delete from MyObject as m where m.id = ?1 and m.user.id = ?#{ principal?.id }") @Override void delete(MyObject entity); @Modifying @Query("delete from MyObject as m where m.user.id = ?#{ principal?.id }") @Override void deleteAll(); @Query("select 1 from MyObject as m where m.id = ?1 and m.user.id = ?#{ principal?.id }") @Override boolean exists(Integer integer); 

警告。 查询可能有错误。 我没时间测试它。

也可以通过在自定义Spring存储库事件处理程序中实现检查来实现。 请参阅@HandleBeforeCreate@HandleBeforeUpdate@HandleBeforeDelete

或者,您可以使用基于权限的表达式,例如使用ACL或自定义表达式,您可以编写@PreAuthorize("hasPermission(#id, 'MyObject', 'DELETE')")