当 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 过滤的集成测试,但我遇到了问题:

我想按以下方式进行测试:

   this.mockMvc = webAppContextSetup(super.webApplicationContext)
            .apply(springSecurity(CSRFFilter.class)) //This is just a showcase of that I pretend
            .alwaysDo(print())
            .build();

我如何有选择地将单个过滤器(如 CSRFFilter)应用于我的集成测试而不是通用 SecurityMockMvcConfigurers.springSecurity()?

请注意,此答案附有完整且有效的示例。

这种问题很有意思。因为它是这样的

  1. 确定了一个问题,该问题未在 Stack Overflow 问题中公开
  2. 有解决问题的建议
  3. 建议的解决方案成为问题,但我们不知道它是最佳解决方案

所以我不确定您是否应该在测试中修改应用程序的过滤器链。最终结果是您不是在测试应用程序,而是在测试永远不会投入生产的修改后的应用程序。

为了怀疑的利益而提出的问题是最好的解决方案,这是可能的。这是我的做法

我创建了一个 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();
    }
}

我相信这应该可以解决您的难题。