'需要ServletContext来配置默认的servlet处理'在spring boot

时间:2015-11-20 17:37:54

标签: spring-security spring-boot

我将Spring MVC servlet 3.1应用程序移到Spring Boot 1.3.0上,当我将@EnableGlobalMethodSecurity注释添加到我的一个Java配置类时,我在启动时遇到异常(完整地在下面) )。

我将WebSecurityConfigurerAdapter子类化为我的春季安全支持(以前对我有用)

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityAuthorisationConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(final HttpSecurity http) throws Exception {
    http.csrf()...

即使没有其他依赖@Autowired进入类,启动也会失败。如果删除@EnableGlobalMethodSecurity注释,启动将成功,但显然没有方法安全性。大多数其他Web安全SO帖子似乎是由于安全配置无法在调度程序servlet之前启动,但在我的安全配置中没有其他依赖项,我无法理解为什么会发生这种情况。

我已经尝试了很多方法来启动应用程序并更改了安全配置的@Order,但无济于事。

我当前的应用程序入口点看起来像这样,虽然我也尝试使用自动魔法调度程序进行初始化,但我遇到了同样的问题:

@Configuration
@EnableAutoConfiguration
@ComponentScan(basePackages = { "com.myapp.config.web", "com.myapp.config.app" })
public class Application extends SpringBootServletInitializer {
        private static Class<Application> applicationClass = Application.class;

        public static void main(final String[] args) throws Exception {
            SpringApplication.run(applicationClass, args);
        }

        @Autowired
        private AuditLogger auditLogger;

        @Override
        public void onStartup(final ServletContext container) throws ServletException {
            final AnnotationConfigWebApplicationContext rootContext = createRootContext(container);

            setUpSessionConfig(container);

            setUpMdcLoggingFilter(container);

            setAllUndefinedRequestsToUtf8(container);

            setUpAuditLogging(container);

            addSecurityFilter(container);

            addUpdateExpiredPasswordFilter(container);

            createDispatcher(container, rootContext);
        }

        private void setUpSessionConfig(final ServletContext container) {
            container.getSessionCookieConfig().setHttpOnly(true);
            container.setSessionTrackingModes(asSet(SessionTrackingMode.COOKIE));
        }

        private void setUpMdcLoggingFilter(final ServletContext container) {
            final Dynamic mdcFilter = container.addFilter("mdcInsertingFilter",
                    new DelegatingFilterProxy(mdcInsertingFilter()));
            mdcFilter.addMappingForUrlPatterns(null, true, "/*");
        }

        private void addUpdateExpiredPasswordFilter(final ServletContext container) {
            final Dynamic filter = container.addFilter("updateExpiredPasswordFilter",
                    new DelegatingFilterProxy(updateExpiredPasswordFilter()));
            filter.addMappingForUrlPatterns(null, true, "/*");
        }

        private void setUpAuditLogging(final ServletContext container) {
            final Dynamic auditLoggingFilter = container.addFilter("auditLogFilter",
                    new DelegatingFilterProxy(auditLogFilter()));
            auditLoggingFilter.addMappingForUrlPatterns(null, true, "/*");

        }

        private void addSecurityFilter(final ServletContext container) {
            final Dynamic securityFilter =
                    container.addFilter(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME,
                            DelegatingFilterProxy.class);
            securityFilter.addMappingForUrlPatterns(null, true, "/*");
        }

        private AnnotationConfigWebApplicationContext createRootContext(final ServletContext servletContext) {
            final AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
            rootContext.register(AppConfig.class);
            rootContext.setServletContext(servletContext);

            servletContext.addListener(new ContextLoaderListener(rootContext));
            servletContext.setInitParameter("spring.profiles.default", "production");
            return rootContext;
        }

        private void setAllUndefinedRequestsToUtf8(final ServletContext container) {
            final FilterRegistration filter = container.addFilter("encodingFilter", OrderedCharacterEncodingFilter.class);
            filter.setInitParameter("encoding", "UTF-8");
            filter.addMappingForUrlPatterns(null, true, "/*");
        }

        private void createDispatcher(final ServletContext container,
                final AnnotationConfigWebApplicationContext rootContext) {
            final DispatcherServlet dispatcherServlet = new DispatcherServlet(rootContext);
            final ServletRegistration.Dynamic dispatcher =
                    container.addServlet("myServlet", dispatcherServlet);

            dispatcher.setLoadOnStartup(1);
            dispatcher.addMapping("/");
        }

        @Bean
        public AuditLogFilter auditLogFilter() {
            final AuditLogFilter auditLogFilter = new AuditLogFilter();
            auditLogFilter.setAuditLogger(auditLogger);
            auditLogFilter.setIgnoredPaths("/resources,/webjars");
            return auditLogFilter;
        }

        @Bean
        public UpdateExpiredPasswordFilter updateExpiredPasswordFilter() {
            final UpdateExpiredPasswordFilter filter = new UpdateExpiredPasswordFilter();
            filter.setPasswordUpdateFormPath("/user/change_password");
            filter.setPasswordUpdatePath("user/change_password");
            filter.setLogoutPath("/logout");
            filter.setIgnoredPaths("/resources,/webjars");
            return filter;
        }

        @Bean(name = "mdcInsertingFilter")
        public MDCInsertingServletFilter mdcInsertingFilter() {
            return new MDCInsertingServletFilter();
        }
}

虽然我不一定希望得到一个全面的解决方案,但知道从哪里开始寻找问题的原因是非常有用的。这是一个错误吗?这可能与我创建应用程序的方式有关吗?

堆栈追踪:

  

2015-11-20 17:18:02.337 ERROR 80806 --- [main] o.s.boot.SpringApplication:应用程序启动失败   org.springframework.beans.factory.BeanCreationException:创建名称为&#39; defaultServletHandlerMapping&#39;在类路径资源中定义[org / springframework / boot / autoconfigure / web / WebMvcAutoConfiguration $ EnableWebMvcConfiguration.class]:通过工厂方法的Bean实例化失败;嵌套异常是org.springframework.beans.BeanInstantiationException:无法实例化[org.springframework.web.servlet.HandlerMapping]:工厂方法&#39; defaultServletHandlerMapping&#39;抛出异常;嵌套异常是java.lang.IllegalArgumentException:需要ServletContext来配置默认的servlet处理       在org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)〜[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]       在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123)~ [spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]       在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018)〜[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]       在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)〜[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]       在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)〜[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]       at org.springframework.beans.factory.support.AbstractBeanFactory $ 1.getObject(AbstractBeanFactory.java:306)〜[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]       在org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)〜[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]       在org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)〜[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]       在org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)〜[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]       at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)~ [spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]       在org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:838)〜[spring-context-4.2.3.RELEASE.jar:4.2.3.RELEASE]       在org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537)〜[spring-context-4.2.3.RELEASE.jar:4.2.3.RELEASE]       at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)~ [spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]       在org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752)[spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]       在org.springframework.boot.SpringApplication.doRun(SpringApplication.java:347)[spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]       在org.springframework.boot.SpringApplication.run(SpringApplication.java:295)[spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]       在org.springframework.boot.SpringApplication.run(SpringApplication.java:1112)[spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]       在org.springframework.boot.SpringApplication.run(SpringApplication.java:1101)[spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]       在com.amberhill.web.Application.main(Application.java:51)[bin /:na]   引起:org.springframework.beans.BeanInstantiationException:无法实例化[org.springframework.web.servlet.HandlerMapping]:工厂方法&#39; defaultServletHandlerMapping&#39;抛出异常;嵌套异常是java.lang.IllegalArgumentException:需要ServletContext来配置默认的servlet处理       在org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)〜[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]       在org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)〜[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]       ...省略了18个常见帧   引起:java.lang.IllegalArgumentException:需要ServletContext来配置默认的servlet处理       在org.springframework.util.Assert.notNull(Assert.java:115)〜[spring-core-4.2.3.RELEASE.jar:4.2.3.RELEASE]       在org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer。(DefaultServletHandlerConfigurer.java:53)〜[spring-webmvc-4.2.3.RELEASE.jar:4.2.3.RELEASE]       在org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.defaultServletHandlerMapping(WebMvcConfigurationSupport.java:450)〜[spring-webmvc-4.2.3.RELEASE.jar:4.2.3.RELEASE]       at org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration $ EnableWebMvcConfiguration $$ EnhancerBySpringCGLIB $$ 5204f0e6.CGLIB $ defaultServletHandlerMapping $ 34()〜[spring-boot-autoconfigure-1.3.0.RELEASE.jar:1.3.0.RELEASE]       at org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration $ EnableWebMvcConfiguration $$ EnhancerBySpringCGLIB $$ 5204f0e6 $$ FastClassBySpringCGLIB $$ 7ec661f1.invoke()〜[spring-boot-autoconfigure-1.3.0.RELEASE.jar:1.3.0。发布]       在org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)〜[spring-core-4.2.3.RELEASE.jar:4.2.3.RELEASE]       在org.springframework.context.annotation.ConfigurationClassEnhancer $ BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:318)〜[spring-context-4.2.3.RELEASE.jar:4.2.3.RELEASE]       at org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration $ EnableWebMvcConfiguration $$ EnhancerBySpringCGLIB $$ 5204f0e6.defaultServletHandlerMapping()〜[spring-boot-autoconfigure-1.3.0.RELEASE.jar:1.3.0.RELEASE]       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)〜[na:1.8.0_11]       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)〜[na:1.8.0_11]       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)〜[na:1.8.0_11]       在java.lang.reflect.Method.invoke(Method.java:483)〜[na:1.8.0_11]       在org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)〜[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]       ...省略了19个常见帧

1 个答案:

答案 0 :(得分:2)

我终于设法通过将@EnableGlobalMethodSecurity(prePostEnabled = true)注释从WebSecurityConfigurerAdapter实现移动到它自己的配置类扩展GlobalMethodSecurityConfiguration来配置身份验证管理器来实现这一点。

我觉得这是一个解决方法,但至少它是固定的。

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
    @Override
    public void configure(final AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider());
    }

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        final DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setPasswordEncoder(new StandardPasswordEncoder());
        authProvider.setUserDetailsService(userDetailsService());
        return authProvider;
    }

    @Bean
    public MyUserDetailsService userDetailsService() {
        return new MyUserDetailsService(...);
    }

}