springSecurityFilterChain bean not found using Moc

2019-08-22 05:41发布

I'm testing a spring rest controller using spring MockMVC. I am able to execute mock http requests and verify the response. My setup autowires the WebApplicationContext:

@RunWith(SpringRunner.class)
@WebAppConfiguration
@ContextConfiguration
public class MyTestClass {

@Autowired
private WebApplicationContext webAppContext;

private MockMvc mockMvc;

@Before
public void setup() {
    this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webAppContext)
            .apply(springSecurity()).build();
}

To tell MockMVC what controllers to initialize and add to the context I have an internal config class:

@Configuration
@ComponentScan(
        basePackages = {"com.acme"},
        useDefaultFilters = false,
        includeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value={MyRestController.class, MyRestControllerDependency.class})
        })
@EnableWebMvc
static class MyTestClassConfig implements WebMvcConfigurer {

    @Bean
    public MyClassRepository myClassRepository() {
        return Mockito.mock(MyClassRepository.class);
    }

And this works like a charm. MockMVC spins up a container with a context that loaded MyRestController and serves the urls mapped by MyRestController. Now, some of MyRestControllers methods are annotated with: @PreAuthorize("hasAuthority('ADMINISTRATOR')") so the next step is to test that.

Reading the Integration part of the Spring security testing guide spring security and test-mockmvc it seems all I should do is call the org.springframework.security.test.web.servlet.setup.springSecurity() in the MockMvcBuilders .apply() function calls.

This does not work, I get:

java.lang.IllegalStateException: springSecurityFilterChain cannot be null. Ensure a Bean with the name springSecurityFilterChain implementing Filter is present or inject the Filter to be used.

I tried adding a bean definition to my internal config class like so:

    Filter springSecurityFilterChain() {
        return new FilterChainProxy();
    }

While this does provide a springSecurityFilterChain, the instance is empty and when I run the test I get a NPE:

java.lang.NullPointerException
at org.springframework.security.web.FilterChainProxy.getFilters(FilterChainProxy.java:224)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)

Which, is understandable, by instantiating the FilterChainProxy directly, it is indeed empty.

I suspect I need to configure my component scan to include springs' instances of the FilterChainProxy. If that is the issue, I don't know what classes I should include. I have tried including all the classes:

        includeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value={TenantAPI.class, TenantManager.class}),
                          @ComponentScan.Filter(type = FilterType.REGEX, pattern="^org\\.springframework\\.security.*")})

But this gives the same error: "Ensure a Bean with the name springSecurity.." as when I run the test without the additional Regex filter.

Does anyone know how I can get the springSecurityFilterChain when I am being picky with the internal classes I let MockMVC instantiate?

1条回答
对你真心纯属浪费
2楼-- · 2019-08-22 06:14

I assume you must have a @Configuration class somewhere that extends WebSecurityConfigurerAdapter? This is the configuration you need to set up Spring security.

You need to include this class in your component scan in your test configuration.

查看更多
登录 后发表回答