我将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个常见帧
答案 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(...);
}
}