Spring Security 5.8.9迁移至6时Bean缺失问题求助
Spring Security 5.8.9迁移至6.x时的上下文配置异常问题
我正在基于Spring Security 5.8.9执行Spring Security 6的迁移准备步骤,遇到了无法解决的异常情况:
第一个异常场景
应用按推荐修改后启动时抛出错误:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'mvcHandlerMappingIntrospector' available: A Bean named mvcHandlerMappingIntrospector of type org.springframework.web.servlet.handler.HandlerMappingIntrospector is required to use MvcRequestMatcher. Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext.
尝试解决后的第二个异常场景
查阅文档后得知需要将Spring Security配置放在Servlet上下文而非根应用上下文,于是我将安全配置从WebServletInitializer的getRootConfigClasses移至getServletConfigClasses中,但此时应用完全无法加载,日志报错:
22-Feb-2024 16:45:09.963 INFO [main] org.apache.catalina.core.ApplicationContext.log 2 Spring WebApplicationInitializers detected on classpath 22-Feb-2024 16:45:10.028 INFO [main] org.apache.catalina.core.ApplicationContext.log Initializing Spring root WebApplicationContext 22-Feb-2024 16:45:52.348 SEVERE [main] org.apache.catalina.core.StandardContext.filterStart Exception starting filter [springSecurityFilterChain] org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'springSecurityFilterChain' available at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:874) at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1358) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:309) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:213) at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1162) at org.springframework.web.filter.DelegatingFilterProxy.initDelegate(DelegatingFilterProxy.java:334) at org.springframework.web.filter.DelegatingFilterProxy.initFilterBean(DelegatingFilterProxy.java:239) at org.springframework.web.filter.GenericFilterBean.init(GenericFilterBean.java:239) at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:262) at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:101)
我无法理解为何安全配置在根应用上下文能正常注册,移至Servlet上下文后就不行了。
配置信息
SecurityApplicationInitializer.java
public class SecurityApplicationInitializer extends AbstractSecurityWebApplicationInitializer { @Override protected boolean enableHttpSessionEventPublisher() { // Publishes HttpSessionApplicationEvents to the Spring Root WebApplicationContext return true; } @Override protected void beforeSpringSecurityFilterChain( ServletContext servletContext ) { // TODO: move into SecurityConfiguration? SecurityContextHolder.setStrategyName( SecurityContextHolder.MODE_INHERITABLETHREADLOCAL ); MultipartFilter multipartFilter = new MultipartFilter(); multipartFilter.setMultipartResolverBeanName( "multipartResolver" ); OriginInterceptor originInterceptor = new OriginInterceptor(); insertFilters( servletContext, multipartFilter, originInterceptor ); } }
MainWebApplicationInitializer.java
public class MainWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override public void onStartup( ServletContext servletContext ) throws ServletException { super.onStartup( servletContext ); servletContext.addListener( new IIOProviderContextListener() ); // TODO: Is it possible to have spring create this and have it register itself? servletContext.addListener( new ConfigureSessionTimeoutListener() ); } @Override protected Class<?>[] getRootConfigClasses() { return new Class<?>[] { SecurityServicesConfiguration.class, MainConfiguration.class }; } @Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[] { WebSecurityConfiguration.class, WebMvcConfiguration.class }; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } @Override protected Filter[] getServletFilters() { CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); characterEncodingFilter.setEncoding( "UTF-8" ); characterEncodingFilter.setForceEncoding( true ); return new Filter[] { characterEncodingFilter }; } }
WebSecurityConfiguration.java
@Configuration @EnableWebSecurity @EnableMethodSecurity public class WebSecurityConfiguration { @Bean public AuthenticationManager authenticationManager( DaoAuthenticationProvider daoAuthenticationProvider ) { return new ProviderManager( daoAuthenticationProvider ); } @Bean public DaoAuthenticationProvider daoAuthenticationProvider( UserDetailsService internalUserDetailsService, PasswordEncoder passwordEncoder ) { DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); daoAuthenticationProvider.setUserDetailsService( internalUserDetailsService ); daoAuthenticationProvider.setPasswordEncoder( passwordEncoder ); return daoAuthenticationProvider; } @Bean public CookieCsrfTokenRepository cookieCsrfTokenRepository() { CookieCsrfTokenRepository cookieCsrfTokenRepository = new CookieCsrfTokenRepository(); cookieCsrfTokenRepository.setCookieHttpOnly( false ); return cookieCsrfTokenRepository; } @Bean public SecurityFilterChain newApiSecurityFilterChain( HttpSecurity http, SessionRegistry sessionRegistry ) throws Exception { return http .securityMatchers( securityMatchers -> securityMatchers .requestMatchers( "/api/**" ) ) .csrf( csrf -> csrf .csrfTokenRepository( cookieCsrfTokenRepository() ) ) .httpBasic( httpBasic -> httpBasic .authenticationEntryPoint( new ApiAuthenticationEntryPoint() ) ) .sessionManagement( sessionManagement -> sessionManagement .maximumSessions( -1 ) .sessionRegistry( sessionRegistry ) ) .build(); } }
临时解决方案(非预期正确方案)
若在根配置类中手动为WebSecurityConfiguration添加HandlerMappingIntrospector Bean,应用可正常加载,但我认为这并非正确解决方案,配置应无需手动添加该Bean且能在Servlet上下文正常加载:
@Bean( name = "mvcHandlerMappingIntrospector" ) public HandlerMappingIntrospector mvcHandlerMappingIntrospector() { return new HandlerMappingIntrospector(); }
内容的提问来源于stack exchange,提问作者Piers Geyman
相关产品推荐
相关产品推荐

