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')")
。