我在使用 MockMvc 测试 Spring Boot 应用程序时遇到了一些问题。
我有以下测试类:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {SpringConfiguration.class, SecurityConfiguration.class})
@IntegrationTest({"server.port=8080"})
@WebAppConfiguration
public class DemoTest {
@Autowired
private EmbeddedWebApplicationContext webApplicationContext;
private MockMvc mockMvc;
@Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
@Test
public void testGetAccountUnauthenticated() throws Exception {
mockMvc.perform(get("/accounts/1").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isUnauthorized());
}
}
这导致 HTTP 200 而不是 401。我启用了组件扫描和自动配置,并且在我的 SecuityConfiguration 类中配置了 spring 安全性,如下所示:
@Configuration
@EnableWebSecurity
@EnableWebMvcSecurity // required for use of @AuthenticationPrincipal in MVC controllers.
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) {
web.debug(true);
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//set up authentication.
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated();
// set up form login
}
}
如果我使用 RestTemplate 进行访问,http://localhost:8080/accounts/1
那么我会得到预期的行为(HTTP 401)。
我已经看到其他示例(例如Spring Boot setup security for testing)建议我使用该方法自动装配FilterChainProxy
并手动添加过滤器。WebApplicationContext.addFilters(filterChainProxy)
然而,这对我来说实际上是失败的(org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.security.web.FilterChainProxy] found
)。
我有两个问题:
- 为什么注入的 WebApplicationContext 不会自动使用 SpringSecurity 过滤器?即使我可以获得 FilterChainProxy 并手动添加它,JavaDoc for EmbeddedWebApplicationContext 状态
上下文中定义的任何 {@link Servlet} 或 {@link Filter} bean 将自动注册到嵌入式 Servlet 容器
结果,我不希望必须手动添加安全过滤器链,因为我(错误地?)由于 Spring Boot 中的自动配置魔法而希望它“正常工作”?
- 为什么应用上下文中没有 FilterChainProxy?同样,也许我对 AutoConfiguration 的期望是不正确的——但我认为这将被配置为上下文配置的一部分。
提前感谢您的任何建议。
编辑
FilterChainProxy 没有被注入的原因是因为我的配置设置为
公共无效配置(WebSecurity web){ web.debug(true);}
这实际上配置了一个org.springframework.security.web.debug.DebugFilter
。无论此调试设置如何,我现在设法获取过滤器的方式如下:
@Resource(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
private Filter securityFilter;
如果我将其添加到 MockMvcBuilder 中,如下所示:
MockMvcBuilders.webAppContextSetup(webApplicationContext).addFilters(securityFilter)
然后它会按预期工作。
但是,我不明白为什么 MockMVC 会忽略过滤器,因为这对于测试请求似乎很重要,因为过滤器中可能发生任何可能影响测试结果的事情。此外,这意味着要正确测试,我需要在 servlet 上下文中查找所有过滤器并建立它们的优先级/url 映射并适当地添加它们。这似乎容易出错且不必要。