You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 16:44:58