2015-07-10 123 views
1

我有一个半工作(如在runnable中)Spring Boot Web应用程序,我试图增加安全性。我有一个OAuth2工作的REST服务,但我也需要WebMvc方面的验证工作。所以我重构的配置我无法得到我做事的方法这方面的工作:Spring ComponentScan导致java.lang.IllegalStateException:ApplicationEventMulticaster未初始化

public class SpringConfigurationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer 
{ 
    @Override 
    protected Class<?>[] getRootConfigClasses() 
    { 
     return new Class[] { AppConfiguration.class }; 
    } 

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

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

} 

@Configuration 
@ComponentScan(basePackages = {"co.sens.rest", "co.sens.data", "co.sens.docdata", "co.sens.aggregators"}) 
@Import({ WebMvcConfig.class, OAuth2ServerConfig.class, SecurityConfiguration.class, CustomUserDetailsService.class }) 
public class AppConfiguration { 
} 

因此,意图是,这个扫描的应用程序本身(co.sens组件.rest)以及引用的jar中的外部代码。保持数据访问的主要目的是分开的。

由于这样做,我现在正在收到以下错误,从我能收集的是因为Spring Security太快踢了。它正在尝试为我的自定义UserDetailsS​​ervice Autowire UserRepository。

之前添加AbstractAnnotationConfigDispatcherServletInitializer我能得到它的运行,但我坚持不下去了网络侧安全工作

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'embeddedServletContainerCustomizerBeanPostProcessor': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'methodSecurityConfig': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private co.sens.rest.config.SecurityConfiguration co.sens.rest.config.MethodSecurityConfig.securityConfig; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'securityConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.setContentNegotationStrategy(org.springframework.web.accept.ContentNegotiationStrategy); nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration.setConfigurers(java.util.List); nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'webController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private co.sens.rest.controllers.UsersController co.sens.rest.controllers.web.WebController.usersController; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'usersController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private co.sens.data.Operations co.sens.rest.controllers.UsersController.dataOperations; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'operations': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private co.sens.docdata.DocStoreOperations co.sens.data.Operations.docStoreOperations; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'docStoreOperations': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private co.sens.docdata.repositories.UserRepository co.sens.docdata.DocStoreOperations.userRepository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userRepository': Invocation of init method failed; nested exception is java.lang.IllegalStateException: ApplicationEventMulticaster not initialized - call 'refresh' before multicasting events via the context: org.springframework.boot[email protected]553a3d88: startup date [Fri Jul 10 08:55:21 BST 2015]; root of context hierarchy 
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:547) 
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476) 
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303) 
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) 
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299) 
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) 
at org.springframework.context.support.PostProcessorRegistrationDelegate.registerBeanPostProcessors(PostProcessorRegistrationDelegate.java:232) 
at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:615) 
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:465) 
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118) 
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686) 
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320) 
at org.springframework.boot.SpringApplication.run(SpringApplication.java:957) 
at org.springframework.boot.SpringApplication.run(SpringApplication.java:946) 
at co.sens.rest.Application.main(Application.java:11) 

完整堆栈跟踪:http://pastebin.com/SJLa2pSc

UPDATE

配置:

package co.sens.rest.config; 

@Configuration 
@ComponentScan(basePackages = {"co.sens.data", "co.sens.docdata", "co.sens.aggregators"}) 
public class AppConfiguration { 
} 

public class MessageSecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer { 

} 

@Configuration 
public class OAuth2ServerConfig { 

    private static final String SENS_RESOURCE_ID = "sens"; 

    @Configuration 
    @EnableResourceServer 
    protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter { 

     @Override 
     public void configure(ResourceServerSecurityConfigurer resources) { 
      resources.resourceId(SENS_RESOURCE_ID).stateless(false); //.authenticationEntryPoint(new RestAuthenticationEntryPoint()); //.stateless(false); 
     } 

     @Override 
     public void configure(HttpSecurity http) throws Exception { 

      http 
        .authorizeRequests() 
        .antMatchers("/api").access("#oauth2.hasScope('read') and hasRole('ROLE_USER')"); 

     } 
    } 

    @Configuration 
    @EnableAuthorizationServer 
    protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { 

     @Autowired 
     private TokenStore tokenStore; 

     @Autowired 
     private UserApprovalHandler userApprovalHandler; 

     @Autowired 
     @Qualifier("authenticationManagerBean") 
     private AuthenticationManager authenticationManager; 

     @Autowired 
     private CustomUserDetailsService userDetailsService; 

     @Override 
     public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 
      clients.inMemory().withClient("sensapp") 
        .resourceIds(SENS_RESOURCE_ID) 
        .authorizedGrantTypes("authorization_code", "refresh_token", 
          "password") 
        .authorities("USER") 
        .scopes("read", "write") 
        .secret("secret"); 
     } 

     @Bean 
     public TokenStore tokenStore() { 
      return new InMemoryTokenStore(); 
     } 

     @Override 
     public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { 
      endpoints 
        .tokenStore(tokenStore) 
        .userApprovalHandler(userApprovalHandler) 
        .authenticationManager(authenticationManager) 
        .userDetailsService(userDetailsService); 
     } 

     @Bean 
     @Primary 
     public DefaultTokenServices tokenServices() { 
      DefaultTokenServices tokenServices = new DefaultTokenServices(); 
      tokenServices.setSupportRefreshToken(true); 
      tokenServices.setTokenStore(this.tokenStore); 
      return tokenServices; 
     } 
     @Override 
     public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { 
      oauthServer.realm("sens/client"); 
     } 
    } 

    protected static class Approvals { 

     @Autowired 
     private ClientDetailsService clientDetailsService; 

     @Autowired 
     private TokenStore tokenStore; 

     @Bean 
     public ApprovalStore approvalStore() throws Exception { 
      TokenApprovalStore store = new TokenApprovalStore(); 
      store.setTokenStore(tokenStore); 
      return store; 
     } 

     @Bean 
     @Lazy 
     @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) 
     public SensUserApprovalHandler userApprovalHandler() throws Exception { 
      SensUserApprovalHandler handler = new SensUserApprovalHandler(); 
      handler.setApprovalStore(approvalStore()); 
      handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService)); 
      handler.setClientDetailsService(clientDetailsService); 
      handler.setUseApprovalStore(true); 
      return handler; 
     } 
    } 
} 

public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint { 
    @Override 
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { 
     response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); 
    } 
} 
@Configuration 
@EnableWebSecurity 
public class SecurityConfiguration extends WebSecurityConfigurerAdapter { 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http.authorizeRequests() 
       .antMatchers("/web/**").authenticated() 
       .antMatchers("/login/**", "/resources/**").permitAll() 
       .and() 
       .formLogin().loginProcessingUrl("/login").failureUrl("/login?authorization_error=true").defaultSuccessUrl("/web/home").loginPage("/login").permitAll() 
       .and() 
       .logout().logoutUrl("/logout").logoutSuccessUrl("/login") 
       .permitAll(); 
    } 

    @Autowired 
    private UserDetailsService userDetailsService; 

    @Autowired 
    public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception { 
       auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder()); 
    } 

    @Override 
    @Bean 
    public AuthenticationManager authenticationManagerBean() throws Exception { 
     return super.authenticationManagerBean(); 
    } 
} 
public class ServletInitializer extends AbstractDispatcherServletInitializer { 

    @Override 
    protected WebApplicationContext createServletApplicationContext() { 
     AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); 
     context.scan(ClassUtils.getPackageName(getClass())); 
     return context; 
    } 

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

    @Override 
    protected WebApplicationContext createRootApplicationContext() { 
     return null; 
    } 

    @Override 
    public void onStartup(ServletContext servletContext) throws ServletException { 
     super.onStartup(servletContext); 
     DelegatingFilterProxy filter = new DelegatingFilterProxy("springSecurityFilterChain"); 
     filter.setContextAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher"); 
     servletContext.addFilter("springSecurityFilterChain", filter).addMappingForUrlPatterns(null, false, "/*"); 
    } 

} 
@Configuration 
@EnableWebMvc 
public class WebMvcConfig extends WebMvcConfigurerAdapter { 

    @Override 
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { 
     configurer.enable(); 
    } 

    //@Override 
    public void addResourceHandlers(ResourceHandlerRegistry registry) { 
     registry 
       .addResourceHandler("/resources/**") 
       .addResourceLocations("/resources/") 
       .setCachePeriod(31556926); 
     registry.setOrder(Ordered.HIGHEST_PRECEDENCE); 
    } 

    @Bean 
    public TemplateResolver defaultTemplateResolver() { 
     TemplateResolver result = new ServletContextTemplateResolver(); 
     result.setPrefix("/WEB-INF/templates/"); 
     result.setSuffix(".html"); 
     result.setTemplateMode("LEGACYHTML5"); 
     result.setCacheable(false); // TODO Only for dev 
     return result; 
    } 

    @Bean 
    public SpringTemplateEngine templateEngine(TemplateResolver templateResolver) { 
     SpringTemplateEngine templateEngine = new SpringTemplateEngine(); 
     templateEngine.setTemplateResolver(templateResolver); 
     Set<IDialect> dialects = new HashSet<>(); 
     dialects.add(new SpringSecurityDialect()); 
     templateEngine.setAdditionalDialects(dialects); 
     return templateEngine; 
    } 

    @Bean 
    public ThymeleafViewResolver viewResolver(SpringTemplateEngine templateEngine) { 
     ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); 
     viewResolver.setTemplateEngine(templateEngine); 
     return viewResolver; 
    } 

    @Bean 
    public ContentNegotiatingViewResolver contentViewResolver() throws Exception { 
     ContentNegotiationManagerFactoryBean contentNegotiationManager = new ContentNegotiationManagerFactoryBean(); 
     contentNegotiationManager.addMediaType("json", MediaType.APPLICATION_JSON); 

     MappingJackson2JsonView defaultView = new MappingJackson2JsonView(); 
     defaultView.setExtractValueFromSingleKeyModel(true); 

     ContentNegotiatingViewResolver contentViewResolver = new ContentNegotiatingViewResolver(); 
     contentViewResolver.setContentNegotiationManager(contentNegotiationManager.getObject()); 
     contentViewResolver.setDefaultViews(Arrays.<View>asList(defaultView)); 
     return contentViewResolver; 
    } 

    @Bean 
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { 
     return new PropertySourcesPlaceholderConfigurer(); 
    } 
} 

安全调试日志

2015-07-14 14:05:31.352 INFO 12373 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]  : Initializing Spring FrameworkServlet 'dispatcherServlet' 
2015-07-14 14:05:31.352 INFO 12373 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet  : FrameworkServlet 'dispatcherServlet': initialization started 
2015-07-14 14:05:31.387 INFO 12373 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet  : FrameworkServlet 'dispatcherServlet': initialization completed in 35 ms 
2015-07-14 14:05:31.460 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/oauth/token'] 
2015-07-14 14:05:31.460 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/web/home'; against '/oauth/token' 
2015-07-14 14:05:31.460 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/oauth/token_key'] 
2015-07-14 14:05:31.460 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/web/home'; against '/oauth/token_key' 
2015-07-14 14:05:31.460 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/oauth/check_token'] 
2015-07-14 14:05:31.460 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/web/home'; against '/oauth/check_token' 
2015-07-14 14:05:31.460 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher : No matches found 
2015-07-14 14:05:31.460 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using org.springframework.security.oauth2.config.annotation.web.c[email protected]7d97df04 
2015-07-14 14:05:31.461 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher : matched 
2015-07-14 14:05:31.462 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /web/home at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter' 
2015-07-14 14:05:31.462 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /web/home at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter' 
2015-07-14 14:05:31.463 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /web/home at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter' 
2015-07-14 14:05:31.463 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.se[email protected]63d700f9 
2015-07-14 14:05:31.463 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /web/home at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter' 
2015-07-14 14:05:31.463 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/web/home'; against '/logout' 
2015-07-14 14:05:31.464 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /web/home at position 5 of 11 in additional filter chain; firing Filter: 'OAuth2AuthenticationProcessingFilter' 
2015-07-14 14:05:31.464 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.o.p.a.BearerTokenExtractor   : Token not found in headers. Trying request parameters. 
2015-07-14 14:05:31.464 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.o.p.a.BearerTokenExtractor   : Token not found in request parameters. Not an OAuth2 request. 
2015-07-14 14:05:31.464 DEBUG 12373 --- [nio-8080-exec-1] p.a.OAuth2AuthenticationProcessingFilter : No token in request, will continue chain. 
2015-07-14 14:05:31.464 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /web/home at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter' 
2015-07-14 14:05:31.464 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /web/home at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter' 
2015-07-14 14:05:31.465 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /web/home at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter' 
2015-07-14 14:05:31.466 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.w.a.AnonymousAuthenticationFilter : Populated SecurityContextHolder with anonymous token: 'org.sprin[email protected]9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS' 
2015-07-14 14:05:31.467 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /web/home at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter' 
2015-07-14 14:05:31.467 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.w.session.SessionManagementFilter : Requested session ID 09564785AF0DDD41AB2645CEEE04E79E is invalid. 
2015-07-14 14:05:31.467 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /web/home at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter' 
2015-07-14 14:05:31.467 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /web/home at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor' 
2015-07-14 14:05:31.467 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/web/home'; against '/api' 
2015-07-14 14:05:31.467 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor : Public object - authentication not attempted 
2015-07-14 14:05:31.468 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /web/home reached end of additional filter chain; proceeding with original chain 
2015-07-14 14:05:31.622 ERROR 12373 --- [nio-8080-exec-1] org.thymeleaf.TemplateEngine    : [THYMELEAF][http-nio-8080-exec-1] Exception processing template "index": Error retrieving value for property "username" of authentication object of class org.springframework.security.authentication.AnonymousAuthenticationToken (index) 
2015-07-14 14:05:31.624 DEBUG 12373 --- [nio-8080-exec-1] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed 
2015-07-14 14:05:31.626 ERROR 12373 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateProcessingException: Error retrieving value for property "username" of authentication object of class org.springframework.security.authentication.AnonymousAuthenticationToken (index)] with root cause 

回答

1

如果您在使用Spring启动时,您应该删除您SpringConfigurationInitializer,并使用SpringBootServletInitializer。例如:

@SpringBootApplication 
public class Application extends SpringBootServletInitializer { 

    @Override 
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 
     return application.sources(Application.class); 
    } 

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

有关详细信息,请参阅Spring Boot参考。

+0

我已经这样做了,但我得到了完全相同的错误 –

+0

作为Spring Boot应用程序运行时它工作吗?你能提供完整的堆栈跟踪吗? –

+0

添加了stacktrace链接,因为这个帖子太大了。我使用gradle bootRun定义在我的IDE中运行。 –

相关问题