次要版本更新后的Spring Security异常:“请确保Spring Security& Spring MVC在共享的ApplicationContext中配置”

时间:2018-01-29 22:46:42

标签: java spring spring-mvc spring-security

将我的Spring框架从4.3.13稍微升级到4.3.14并将spring-security 4.2.3升级到4.2.4后,我的Web应用程序无法初始化(Tomcat 8.5.23,JDK 1.8。 0_152),出现以下错误:

[DEBUG] Retrieved dependent beans for bean 'springSecurityFilterChain': [webSecurityExpressionHandler]
[WARN] Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException:
       Error creating bean with name 'springSecurityFilterChain' defined in org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration:
       Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is 
         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.

抛出此异常的类是CorsConfigurer.MvcCorsFilter,它是spring-security的一部分。

我在这个错误(SPR-16301)上找到了一个有用的线程,它解释了这个异常是在新版本的Spring(5.0.3和4.3.14,{{{ {3}}在同一天)。

我的WebConfig类具有@EnableWebSecurity注释,如上面的主题中所述,导入DelegatingWebMvcConfiguration,它声明了released

本质上,该线程表明已声明了多个上下文(根上下文和子上下文),并且我可能已在多个上下文中启用了Spring Security。

但是,在我的案例中,我没有看到解决方案。我有重复/重叠注释吗?我是否在WebInitializer课程中错误地加载了Root和Security配置?

我的Spring配置类列在下面(我的AuthenticationProvider除外)。

WebInitializer.java

package com.x.spring;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public final class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer
{
    @Override
    protected Class<?>[] getRootConfigClasses()
    {
        return new Class<?>[] {RootConfig.class, WebSecurityConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses()
    {
        return new Class<?>[] {WebConfig.class};
    }

    @Override
    protected String[] getServletMappings()
    {
        return new String[] {"/"};
    }

    @Override
    protected DispatcherServlet createDispatcherServlet(final WebApplicationContext servletAppContext)
    {
        final DispatcherServlet dispatcherServlet = (DispatcherServlet) super.createDispatcherServlet(servletAppContext);
        dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
        return dispatcherServlet;
    }
}

RootConfig.java

package com.x.spring;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@ComponentScan(basePackages = {"com.x.spring.controller"}, excludeFilters = {@Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class)})
public class RootConfig
{
}

WebConfig.java

package com.x.spring;

import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.tiles3.TilesConfigurer;
import org.springframework.web.servlet.view.tiles3.TilesViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan("com.x.spring.controller")
public class WebConfig extends WebMvcConfigurerAdapter
{
    @Bean
    public ViewResolver viewResolver()
    {
        final TilesViewResolver resolver = new TilesViewResolver();
        return resolver;
    }

    @Bean
    public TilesConfigurer tilesConfigurer()
    {
        final TilesConfigurer tiles = new TilesConfigurer();
        tiles.setDefinitions(new String[] {"/WEB-INF/tiles.xml"});
        tiles.setCheckRefresh(true);
        return tiles;
    }

    @Bean
    public CommonsMultipartResolver multipartResolver()
    {
        final CommonsMultipartResolver resolver = new CommonsMultipartResolver();
        resolver.setMaxUploadSize(10000000);
        return resolver;
    }

    // These methods enable '.' in RequestMappings.
    @Override
    public final void configurePathMatch(final PathMatchConfigurer configurer)
    {
        configurer.setUseRegisteredSuffixPatternMatch(true);
        return;
    }

    @Override
    public final void addResourceHandlers(final ResourceHandlerRegistry registry)
    {
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/images/**").addResourceLocations("/images/");
        return;
    }

    @Override
    public void addCorsMappings(final CorsRegistry registry)
    {
        registry.addMapping("/**");
        return;
    }
}

WebSecurityConfig.java

package com.x.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

import com.x.spring.security.XAuthenticationProvider;

/**
 * Spring web security configuration.
 * This class must be registered with WebInitializer.
 */
@Configuration
@EnableWebSecurity
@ComponentScan("com.x.spring.security")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
    @Autowired
    private XAuthenticationProvider authenticationProvider;

    /**
     * https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/
     */
    public WebSecurityConfig()
    {
        super();
        return;
    }

    @Override
    public void configure(final WebSecurity web) throws Exception
    {
        super.configure(web);
        return;
    }

    @Override
    protected void configure(final HttpSecurity http) throws Exception
    {
        http
        .csrf().disable()
        .cors()
        .and().headers().frameOptions().sameOrigin()
        .and()
          .authorizeRequests()
            .antMatchers("/my-account").hasAuthority("USER")
            .anyRequest().permitAll()
        .and().httpBasic().realmName("X")
        .and().formLogin().loginPage("/login")
        .and().logout().logoutSuccessUrl("/")
        .and().rememberMe().key("XSecured")
        ;

        return;
    }

    @Override
    protected void configure(final AuthenticationManagerBuilder auth) throws Exception
    {
        auth.authenticationProvider(this.authenticationProvider);
        return;
    }
}

WebSecurityInitializer.java

package com.x.spring;

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

/**
 * This class is discovered by Spring and registers the DelegatingFilterProxy with the web container.
 * It will intercept requests coming into the application and delegate them to a bean whose ID is springSecurityFilterChain.
 */
public final class WebSecurityInitializer extends AbstractSecurityWebApplicationInitializer
{
}

1 个答案:

答案 0 :(得分:2)

初始化错误是由重复的上下文引起的。具体来说,RootConfig类与WebConfig类是多余的。通过删除RootConfig并更改WebInitializer.getRootConfigClasses()以返回WebConfig而不是RootConfigWebInitializer.getServletConfigClasses()来返回null来解决此问题。

我的工作WebInitializer课程如下。除了删除RootConfig之外,其他类不需要进行任何更改。

<强> WebInitializer.java

package com.x.spring;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public final class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer
{
    @Override
    protected Class<?>[] getRootConfigClasses()
    {
        return new Class<?>[] {WebConfig.class, WebSecurityConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses()
    {
        return null;
    }

    @Override
    protected String[] getServletMappings()
    {
        return new String[] {"/"};
    }

    @Override
    protected DispatcherServlet createDispatcherServlet(final WebApplicationContext servletAppContext)
    {
        final DispatcherServlet dispatcherServlet = (DispatcherServlet) super.createDispatcherServlet(servletAppContext);
        dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
        return dispatcherServlet;
    }