当 MockMvc 不可自动装配时,从 Spring Security 选择性地将单个过滤器应用于 MockMvc
Apply selectively a single filter to MockMvc from Spring Security when it is not autowirable
我的 WebSecurityConfigurerAdapter 定义为 http.csrf().csrfTokenRepository(csrfTokenRepository());
我想做一个只激活 CSRF 过滤的集成测试,但我遇到了问题:
- CSRFTokenRepository 未在上下文中公开
- CSRFilter 似乎没有在 Spring
的上下文中作为 bean 公开
我想按以下方式进行测试:
this.mockMvc = webAppContextSetup(super.webApplicationContext)
.apply(springSecurity(CSRFFilter.class)) //This is just a showcase of that I pretend
.alwaysDo(print())
.build();
我如何有选择地将单个过滤器(如 CSRFFilter)应用于我的集成测试而不是通用 SecurityMockMvcConfigurers.springSecurity()?
请注意,此答案附有完整且有效的示例。
这种问题很有意思。因为它是这样的
- 确定了一个问题,该问题未在 Stack Overflow 问题中公开
- 有解决问题的建议
- 建议的解决方案成为问题,但我们不知道它是最佳解决方案
所以我不确定您是否应该在测试中修改应用程序的过滤器链。最终结果是您不是在测试应用程序,而是在测试永远不会投入生产的修改后的应用程序。
为了怀疑的利益而提出的问题是最好的解决方案,这是可能的。这是我的做法
我创建了一个 custom filter 在执行任何其他过滤器之前 returns 500 错误。
static class FiveHundredFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
response.setStatus(500);
response.getWriter().write("TEST FILTER CHAIN");
}
}
然后我创建了一个 BeanPostProcessor
将这个过滤器添加到我所有的过滤器链中。您可以 select 将其添加到此处。
static class SecurityFilterChainPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("springSecurityFilterChain".equals(beanName)) {
FilterChainProxy fcp = (FilterChainProxy) bean;
for (SecurityFilterChain fc : fcp.getFilterChains()) {
fc.getFilters().add(0, new FiveHundredFilter());
}
}
return bean;
}
}
最后我在我的应用程序上下文中将 SecurityFilterChainPostProcessor
作为 bean 公开
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(basePackages = "org/springframework/security/community/samples")
public static class SpringBootApplicationTestConfig {
@Bean
SecurityFilterChainPostProcessor securityFilterChainPostProcessor() {
return new SecurityFilterChainPostProcessor();
}
}
我相信这应该可以解决您的难题。
我的 WebSecurityConfigurerAdapter 定义为 http.csrf().csrfTokenRepository(csrfTokenRepository());
我想做一个只激活 CSRF 过滤的集成测试,但我遇到了问题:
- CSRFTokenRepository 未在上下文中公开
- CSRFilter 似乎没有在 Spring 的上下文中作为 bean 公开
我想按以下方式进行测试:
this.mockMvc = webAppContextSetup(super.webApplicationContext)
.apply(springSecurity(CSRFFilter.class)) //This is just a showcase of that I pretend
.alwaysDo(print())
.build();
我如何有选择地将单个过滤器(如 CSRFFilter)应用于我的集成测试而不是通用 SecurityMockMvcConfigurers.springSecurity()?
请注意,此答案附有完整且有效的示例。
这种问题很有意思。因为它是这样的
- 确定了一个问题,该问题未在 Stack Overflow 问题中公开
- 有解决问题的建议
- 建议的解决方案成为问题,但我们不知道它是最佳解决方案
所以我不确定您是否应该在测试中修改应用程序的过滤器链。最终结果是您不是在测试应用程序,而是在测试永远不会投入生产的修改后的应用程序。
为了怀疑的利益而提出的问题是最好的解决方案,这是可能的。这是我的做法
我创建了一个 custom filter 在执行任何其他过滤器之前 returns 500 错误。
static class FiveHundredFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
response.setStatus(500);
response.getWriter().write("TEST FILTER CHAIN");
}
}
然后我创建了一个 BeanPostProcessor
将这个过滤器添加到我所有的过滤器链中。您可以 select 将其添加到此处。
static class SecurityFilterChainPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("springSecurityFilterChain".equals(beanName)) {
FilterChainProxy fcp = (FilterChainProxy) bean;
for (SecurityFilterChain fc : fcp.getFilterChains()) {
fc.getFilters().add(0, new FiveHundredFilter());
}
}
return bean;
}
}
最后我在我的应用程序上下文中将 SecurityFilterChainPostProcessor
作为 bean 公开
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(basePackages = "org/springframework/security/community/samples")
public static class SpringBootApplicationTestConfig {
@Bean
SecurityFilterChainPostProcessor securityFilterChainPostProcessor() {
return new SecurityFilterChainPostProcessor();
}
}
我相信这应该可以解决您的难题。