Annotating the WebSecurityConfigurerAdapter with @Configuration causes config to be called twice
When I create WebSecurityConfigurerAdapter
, it registers twice. I created a configuration exactly the same as the Hello Web Security Configuration example from the reference docs.
The configuration works as expected, although beans and filter chain are registered twice as shown in the tomcat output.
00:32:01 INFO : Root WebApplicationContext: initialization started
00:32:01 INFO : Refreshing Root WebApplicationContext: startup date [Thu Oct 09 00:32:01 EST 2014]; root of context hierarchy
00:32:01 INFO : Registering annotated classes: [class com.acme.app.config.SecurityConfig]
______________
00:32:02 INFO : Creating filter chain: org.springframework.security.web.util.matcher.AnyRequestMatcher@1, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@26eed435, org.springframework.security.web.context.SecurityContextPersistenceFilter@cd9947, org.springframework.security.web.header.HeaderWriterFilter@354e8394, org.springframework.security.web.csrf.CsrfFilter@54fb62e3, org.springframework.security.web.authentication.logout.LogoutFilter@1df9cd96, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@4da923c6, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@1ee94efd, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@7d4b5722, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@26dde6a8, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@7c58b660, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@6fd12384, org.springframework.security.web.session.SessionManagementFilter@24d4cc75, org.springframework.security.web.access.ExceptionTranslationFilter@1709e92c, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@2c46f137]
00:32:02 INFO : Root WebApplicationContext: initialization completed in 565 ms
00:32:02 INFO : FrameworkServlet 'dispatcher': initialization started
00:32:02 INFO : Refreshing WebApplicationContext for namespace 'dispatcher-servlet': startup date [Thu Oct 09 00:32:02 EST 2014]; parent: Root WebApplicationContext
00:32:02 INFO : Registering annotated classes: [class com.acme.app.config.WebConfig]
______________
00:32:02 INFO : Creating filter chain: org.springframework.security.web.util.matcher.AnyRequestMatcher@1, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@52b26dcb, org.springframework.security.web.context.SecurityContextPersistenceFilter@10f4b535, org.springframework.security.web.header.HeaderWriterFilter@561ad054, org.springframework.security.web.csrf.CsrfFilter@4b6e4b62, org.springframework.security.web.authentication.logout.LogoutFilter@1d424a71, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@2dad3bf4, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@282a0f5c, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@52eeebb7, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@47d4a88e, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@474c5850, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@6fdc40f8, org.springframework.security.web.session.SessionManagementFilter@2978de23, org.springframework.security.web.access.ExceptionTranslationFilter@5bf190dd, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@22b3fc11]
AppInitializer.java
public class AppInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SecurityConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
SecurityConfig.java
@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
System.out.println("______________");
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
SecurityWebApplicationInitializer.java
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
WebConfig.java
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.acme.app")
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("/static/");
}
@Bean
public CookieLocaleResolver getLocaleResolver() {
CookieLocaleResolver bean = new CookieLocaleResolver();
bean.setCookieName("clientlanguage");
bean.setCookieMaxAge(100000);
return bean;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
lci.setParamName("lang");
registry.addInterceptor(lci);
}
@Bean
public TilesConfigurer getTilesConfigurer() {
CustomTilesInitializer ti = new CustomTilesInitializer();
TilesConfigurer res = new TilesConfigurer();
res.setCompleteAutoload(true);
res.setDefinitions("/WEB-INF/**/tiles.xml");
return res;
}
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.tiles();
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
registry.addRedirectViewController("/home", "/");
registry.addViewController("/login").setViewName("login");
registry.addViewController("/aboutme").setViewName("aboutme");
}
}
UPDATE
As @lkrnac pointed out with his answer , the config is loaded twice during annotation WebConfig
@ComponentScan
. I assumed spring would be smart enough not to load the config it previously loaded. I could find classes outside of the config namespace, although that seems annoying. Instead, I decided to provide an exclusion filter as shown below:
@ComponentScan(basePackages = "com.acme.app",
excludeFilters = {
@Filter(type = ASSIGNABLE_TYPE,
value = {
WebConfig.class,
SecurityConfig.class
})
})
This way I can freely create new config classes for my web context without worrying about whether they are included or not.
source to share
The security configuration is in the package com.acme.app.config.SecurityConfig
. This package is scanned into WebConfig
.
So I suspect the context is loaded twice:
- In the Application Initializer
- Checking Components in WebConfig
Try to find SecurityConfig
outside the packagecom.acme.app
source to share