我正在尝试实现细粒度访问控制,同时仍然利用Spring数据休息。
我正在努力保护CrudRepository
,因此用户只能修改或插入属于他们的数据。我正在使用@PreAuthorize
/ @PostAuthorize
和@PreFilter
/ @PostFilter
来锁定当前主体的访问权限。
到目前为止,我的存储库看起来像这样。
public interface MyRepository extends CrudRepository<MyObject, Integer> {
@PreAuthorize("#entity.userId == principal.id")
@Override
<S extends MyObject> S save(S entity);
@PreFilter("filterObject.userId === principal.id")
@Override
<S extends MyObject> Iterable<S> save(Iterable<S> entities);
@PostAuthorize("returnObject.userId == principal.id")
@Override
MyObject findOne(Integer integer);
@PostFilter("filterObject.userId == principal.id")
@Override
Iterable<MyObject> 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的实体,然后执行auth检查。
这种类型的授权是否可以在存储库中进行?
由于
编辑:
感谢ksokol,现在似乎正在运作。
我向@Configuration
类
@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){};
}
}
答案 0 :(得分:18)
从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);
注意。查询可能有错误。我没时间测试它。
答案 1 :(得分:2)
也可以通过在自定义Spring存储库事件处理程序中实现检查来实现。请参阅@HandleBeforeCreate
,@HandleBeforeUpdate
,@HandleBeforeDelete
。
或者,您可以使用基于权限的表达式,例如使用ACL或您的自定义ACL,您可以编写@PreAuthorize("hasPermission(#id, 'MyObject', 'DELETE')")
。