Spring Data Rest 中的存储库访问控制基于用户主体
Repository access control in Spring Data Rest based off user princpal
我正在尝试实施细粒度访问控制,同时仍然利用 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 参数,要么完全采用 none。看来我必须首先 select 具有输入 ID 的实体,然后执行身份验证检查。
在存储库中是否可以进行这种类型的授权?
谢谢
编辑:
多亏了 ksokol,这似乎可以正常工作了。
我在 @Configuration
class
中添加了一个新 bean
@Bean
public EvaluationContextExtension securityExtension() {
return new SecurityEvaluationContextExtensionImpl();
}
此 bean 扩展 EvaluationContextExtensionSupport
并将 getRootObject
覆盖为 return 一个包含我的自定义主体的 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 数据查询中访问 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')")
.
我正在尝试实施细粒度访问控制,同时仍然利用 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 参数,要么完全采用 none。看来我必须首先 select 具有输入 ID 的实体,然后执行身份验证检查。
在存储库中是否可以进行这种类型的授权?
谢谢
编辑:
多亏了 ksokol,这似乎可以正常工作了。
我在 @Configuration
class
@Bean
public EvaluationContextExtension securityExtension() {
return new SecurityEvaluationContextExtensionImpl();
}
此 bean 扩展 EvaluationContextExtensionSupport
并将 getRootObject
覆盖为 return 一个包含我的自定义主体的 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 数据查询中访问 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')")
.