我正在尝试使用SpringBoot+Spring data Mongo+SpringMVC运行一些集成测试
我已经简化和泛化了代码,但它应该能够通过以下测试重现该行为。
正如您从BookRepository
界面中看到的,我希望用户只能检索他拥有的图书(@Query("{ 'ownerName' : '?#{principal?.username})
),并且我正在编写一个测试来执行POST
来保存图书,然后验证图书的所有者设置是否正确。
出于此处问题的目的,我已将测试简化为GET
,然后调用findAll()
问题
执行任何MockMvc
请求后,使用ThreadLocalSecurityContextHolderStrategy#clearContext()
清除SecurityContext
,这会在我尝试调用repository.findAll();
时引发以下异常
java.lang.IllegalArgumentException: Authentication object cannot be null
BookRepository.Java
@RepositoryRestResource
public interface BookRepository extends MongoRepository<Book, String> {
@Query("{ 'ownerName' : ?#{principal?.username} }")
List<Book> findAll();
}
BookCustomRepositoryIntegrationTest.java
/**
* Integrate data mongo + mvc
*/
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class BookCustomRepositoryIntegrationTest {
@Autowired
BookRepository repository;
@Autowired
MockMvc mockMvc;
@Test
@WithMockUser
public void reproduceBug() throws Exception {
repository.findAll(); //Runs allright
mockMvc.perform(get("/books")
.contentType(APPLICATION_JSON_UTF8))
.andExpect(status().isOk());
repository.findAll(); //Throws exception: java.lang.IllegalArgumentException: Authentication object cannot be null
}
}
4条答案
按热度按时间am46iovg1#
您的案例不起作用,因为SecurityContextPersistenceFilter和FilterChainProxy筛选器清除了SecurityConextHolder,但
TestSecurityContextHolder
(由WithSecurityContextTestExecutionListener
填充)仍包含SecurityContext。尝试以下方法:
j2cgzkjk2#
我刚刚找到了一个很好的解决这个问题的办法。您可以在测试配置中注册MockMvcBuilderCustomizer Bean,一切都很正常。
}
[Spring Boot]
nvbavucw3#
我认为可以手动配置
MockMvc
,并按如下方式配置Spring安全性,而不是使用AutoConfigureMockMvc
注解:正如documentation所述:
为了在Spring MVC测试中使用Spring Security,有必要添加Spring Security FilterChainProxy作为筛选器。还需要添加Spring Security的TestSecurityContextHolderPostProcessor,以支持在带有注解的Spring MVC测试中以用户身份运行。这可以使用Spring Security的SecurityMockMvcConfigurers.springSecurity()来完成。
vkc1a9a24#
一种好的做法是将RestController的测试与应用程序的其他层的测试分开。在您的情况下,我认为您不应该将REST调用测试与资源库调用测试混为一谈。
我想您应该进行一个模拟的MVC调用来测试您的“repository.findAll()”
我使用的是Spring Boot 2.6.7(Spring-Security-test-5.6.3.jar)和JUnit5,即使在执行MockMVC http请求之后,TestSecurityConextHolder也会保存安全上下文。
但是如果你没有一个好的变通办法,你需要添加一些东西..事实上,您的repository.findAll()将使用SecurityEvaluationConextExtension来解析安全信息,该扩展使用主SecurityConextHolder(而不是TestSecurityConextHolder)。
所以我想你应该做这样的东西: