Spring-数据和Spring-安全集成
Spring-data and Spring-security integration
文档说通过引入类型为 SecurityEvaluationContextExtension 的 bean,它将提供所有常见的内置安全表达式,如 'principal'、'hasRole' 等。该示例显示了一个简单的集成,使用'principal' 在@Query
@Query("select m from Message m where m.to.id = ?#{ principal?.id }")
现在,如果我想 select 所有消息,而不管 'm.to.id' 是什么,如果主体 hasRole 'ADMIN' 或类似的东西。我已经尝试过这些,但只是遇到了来自 spring-data 解析查询的错误
@Query("select m from Message m where m.to.id = ?#{ principal?.id } or hasRole('ADMIN')")
@Query("select m from Message m where m.to.id = ?#{ principal?.id } or 'true' = ?#{ hasRole('ADMIN') }")
@Query("select m from Message m where m.to.id = ?#{ principal?.id } or 1 = ?#{ hasRole('ADMIN') }")
我们能完成这样的事情吗?基本上,如果用户是普通用户,那么只给他们自己的消息,但管理员用户可以获得所有消息
我们在 spring-data-examples 中有一个类似的用例:
@Query("select o from BusinessObject o where o.owner.emailAddress like ?#{hasRole('ROLE_ADMIN') ? '%' : principal.emailAddress}")
List<BusinessObject> findBusinessObjectsForCurrentUser();
在你的情况下,你可以尝试类似的事情(在提到的 spring-data-examples 项目的上下文中)
存储库方法:
@Query("select o from BusinessObject o where o.owner.id = ?#{principal.id} or 1=?#{hasRole('ROLE_ADMIN') ? 1 : 0}")
List<BusinessObject> findBusinessObjectsForCurrentUserById();
一些测试来验证:
@Test
public void findBusinessObjectsForCurrentUserByIdShouldReturnOnlyBusinessObjectsWhereCurrentUserIsOwner(){
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(tom,"x"));
List<BusinessObject> businessObjects = secureBusinessObjectRepository.findBusinessObjectsForCurrentUserById();
assertThat(businessObjects,hasSize(1));
assertThat(businessObjects,contains(object3));
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(olli,"x"));
businessObjects = secureBusinessObjectRepository.findBusinessObjectsForCurrentUserById();
assertThat(businessObjects,hasSize(2));
assertThat(businessObjects,contains(object1,object2));
}
@Test
public void findBusinessObjectsForCurrentUserByIdShouldReturnAllObjectsForAdmin(){
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(admin,"x", Collections.singleton(new SimpleGrantedAuthority("ROLE_ADMIN"))));
List<BusinessObject> businessObjects = secureBusinessObjectRepository.findBusinessObjectsForCurrentUserById();
assertThat(businessObjects,hasSize(3));
assertThat(businessObjects,contains(object1,object2, object3));
}
文档说通过引入类型为 SecurityEvaluationContextExtension 的 bean,它将提供所有常见的内置安全表达式,如 'principal'、'hasRole' 等。该示例显示了一个简单的集成,使用'principal' 在@Query
@Query("select m from Message m where m.to.id = ?#{ principal?.id }")
现在,如果我想 select 所有消息,而不管 'm.to.id' 是什么,如果主体 hasRole 'ADMIN' 或类似的东西。我已经尝试过这些,但只是遇到了来自 spring-data 解析查询的错误
@Query("select m from Message m where m.to.id = ?#{ principal?.id } or hasRole('ADMIN')")
@Query("select m from Message m where m.to.id = ?#{ principal?.id } or 'true' = ?#{ hasRole('ADMIN') }")
@Query("select m from Message m where m.to.id = ?#{ principal?.id } or 1 = ?#{ hasRole('ADMIN') }")
我们能完成这样的事情吗?基本上,如果用户是普通用户,那么只给他们自己的消息,但管理员用户可以获得所有消息
我们在 spring-data-examples 中有一个类似的用例:
@Query("select o from BusinessObject o where o.owner.emailAddress like ?#{hasRole('ROLE_ADMIN') ? '%' : principal.emailAddress}")
List<BusinessObject> findBusinessObjectsForCurrentUser();
在你的情况下,你可以尝试类似的事情(在提到的 spring-data-examples 项目的上下文中)
存储库方法:
@Query("select o from BusinessObject o where o.owner.id = ?#{principal.id} or 1=?#{hasRole('ROLE_ADMIN') ? 1 : 0}")
List<BusinessObject> findBusinessObjectsForCurrentUserById();
一些测试来验证:
@Test
public void findBusinessObjectsForCurrentUserByIdShouldReturnOnlyBusinessObjectsWhereCurrentUserIsOwner(){
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(tom,"x"));
List<BusinessObject> businessObjects = secureBusinessObjectRepository.findBusinessObjectsForCurrentUserById();
assertThat(businessObjects,hasSize(1));
assertThat(businessObjects,contains(object3));
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(olli,"x"));
businessObjects = secureBusinessObjectRepository.findBusinessObjectsForCurrentUserById();
assertThat(businessObjects,hasSize(2));
assertThat(businessObjects,contains(object1,object2));
}
@Test
public void findBusinessObjectsForCurrentUserByIdShouldReturnAllObjectsForAdmin(){
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(admin,"x", Collections.singleton(new SimpleGrantedAuthority("ROLE_ADMIN"))));
List<BusinessObject> businessObjects = secureBusinessObjectRepository.findBusinessObjectsForCurrentUserById();
assertThat(businessObjects,hasSize(3));
assertThat(businessObjects,contains(object1,object2, object3));
}