在Spring 3.1 Java Config中引用Spring Security配置

我最近切换了大部分Spring配置,在Spring 3.1中使用基于代码的配置。 但是,现在我已经切换,我的Spring Security无法正常工作,并在Tomcat启动时抛出以下错误:

SEVERE: Exception starting filter springSecurityFilterChain org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'springSecurityFilterChain' is defined 

我仍然在XML文件中有Spring Security,并且知道这不能在Spring中转换为Java配置,因为它是一个自定义命名空间,但是,我在我的Java配置文件中引用它。 我还尝试将applicationContext-security.xml配置引用从Java配置移动到我的web.xml,没有任何运气。

 @Configuration @EnableWebMvc @Import(ServicesConfig.class) @ImportResource({ "classpath:applicationContext-security.xml", "classpath:dataSources.xml" }) @ComponentScan(basePackages = "com.foobar") public class WebConfig { // left out Beans for clarity } 

的applicationContext-security.xml文件:

                    

web.xml

   My App   contextClass  org.springframework.web.context.support.AnnotationConfigWebApplicationContext    contextConfigLocation foobar.WebConfig    springSecurityFilterChain org.springframework.web.filter.DelegatingFilterProxy   springSecurityFilterChain /*    org.springframework.web.context.ContextLoaderListener    dispatcher org.springframework.web.servlet.DispatcherServlet  contextClass  org.springframework.web.context.support.AnnotationConfigWebApplicationContext     dispatcher /*   

不要使用security命名空间快捷方式,并将所有spring配置从XML迁移到Java。 它将使您的安全性更加轻松。 迁移到3.1后,我很快就会为我们的项目做这件事。 您可以在此处找到非平凡的几乎普通的bean安全性XML配置示例。

编辑:完成配置(上面链接)迁移。 故意将所有配置放入一个方法中以使其更短并且演示,您不需要为每个filter使用单独的spring bean。 当然最好将复杂的init部分移动到单独的方法(如果需要,标记为@Bean )。 您可以在上面链接的X509AnnotationTest.Config找到工作示例。

 @Bean public FilterChainProxy springSecurityFilterChain() throws Exception { // AuthenticationEntryPoint BasicAuthenticationEntryPoint entryPoint = new BasicAuthenticationEntryPoint(); entryPoint.setRealmName("AppName Realm"); // accessDecisionManager List voters = Arrays.asList(new RoleVoter(), new WebExpressionVoter()); AccessDecisionManager accessDecisionManager = new AffirmativeBased(voters); // SecurityExpressionHandler SecurityExpressionHandler securityExpressionHandler = new DefaultWebSecurityExpressionHandler(); // AuthenticationUserDetailsService UserDetailsByNameServiceWrapper authenticationUserDetailsService = new UserDetailsByNameServiceWrapper(authUserDetailService); authenticationUserDetailsService.afterPropertiesSet(); // PreAuthenticatedAuthenticationProvider PreAuthenticatedAuthenticationProvider preAuthenticatedAuthenticationProvider = new PreAuthenticatedAuthenticationProvider(); preAuthenticatedAuthenticationProvider.setPreAuthenticatedUserDetailsService(authenticationUserDetailsService); preAuthenticatedAuthenticationProvider.afterPropertiesSet(); // AuthenticationManager List providers = Arrays.asList(preAuthenticatedAuthenticationProvider); AuthenticationManager authenticationManager = new ProviderManager(providers); // HttpSessionSecurityContextRepository HttpSessionSecurityContextRepository httpSessionSecurityContextRepository = new HttpSessionSecurityContextRepository(); // SessionRegistry SessionRegistry sessionRegistry = new SessionRegistryImpl(); // ConcurrentSessionControlStrategy ConcurrentSessionControlStrategy concurrentSessionControlStrategy = new ConcurrentSessionControlStrategy(sessionRegistry); // ConcurrentSessionFilter ConcurrentSessionFilter concurrentSessionFilter = new ConcurrentSessionFilter(sessionRegistry); concurrentSessionFilter.afterPropertiesSet(); // SecurityContextPersistenceFilter SecurityContextPersistenceFilter securityContextPersistenceFilter = new SecurityContextPersistenceFilter(httpSessionSecurityContextRepository); // X509AuthenticationFilter X509AuthenticationFilter x509AuthenticationFilter = new X509AuthenticationFilter(); x509AuthenticationFilter.setAuthenticationManager(authenticationManager); x509AuthenticationFilter.afterPropertiesSet(); // RequestCacheAwareFilter RequestCacheAwareFilter requestCacheAwareFilter = new RequestCacheAwareFilter(); // SecurityContextHolderAwareRequestFilter SecurityContextHolderAwareRequestFilter securityContextHolderAwareRequestFilter = new SecurityContextHolderAwareRequestFilter(); // SessionManagementFilter SessionManagementFilter sessionManagementFilter = new SessionManagementFilter(httpSessionSecurityContextRepository, concurrentSessionControlStrategy); // ExceptionTranslationFilter ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(entryPoint); exceptionTranslationFilter.setAccessDeniedHandler(new AccessDeniedHandlerImpl()); exceptionTranslationFilter.afterPropertiesSet(); // FilterSecurityInterceptor FilterSecurityInterceptor filterSecurityInterceptor = new FilterSecurityInterceptor(); filterSecurityInterceptor.setAuthenticationManager(authenticationManager); filterSecurityInterceptor.setAccessDecisionManager(accessDecisionManager); LinkedHashMap> map = new LinkedHashMap>(); map.put(new AntPathRequestMatcher("/**"), Arrays.asList(new SecurityConfig("isAuthenticated()"))); ExpressionBasedFilterInvocationSecurityMetadataSource ms = new ExpressionBasedFilterInvocationSecurityMetadataSource(map, securityExpressionHandler); filterSecurityInterceptor.setSecurityMetadataSource(ms); filterSecurityInterceptor.afterPropertiesSet(); // SecurityFilterChain SecurityFilterChain chain = new DefaultSecurityFilterChain(new AntPathRequestMatcher("/**"), concurrentSessionFilter, securityContextPersistenceFilter, x509AuthenticationFilter, requestCacheAwareFilter, securityContextHolderAwareRequestFilter, sessionManagementFilter, exceptionTranslationFilter, filterSecurityInterceptor); return new FilterChainProxy(chain); } 

对于那些仍在寻找将SpringSecurity XML配置与Java配置Web应用程序一起使用的方法的人。 我使用Spring 3.2.0.RELEASE和SpringSecurity 3.2.0.M1进行了这项工作。 这是解决方案的重要部分

WebAppConfig.java

 package com.foo.webapp; @Configuration @ComponentScan(basePackages = { "com.foo" }) @ImportResource(value = { "/WEB-INF/spring-security.xml" }) public class WebAppConfig { // other beans go here } 

弹簧security.xml文件
请注意,我必须从定义中删除默认的xmlns =“…”。

                

web.xml中

    contextClass  org.springframework.web.context.support.AnnotationConfigWebApplicationContext    contextConfigLocation com.foo.webapp.WebAppConfig    springSecurityFilterChain org.springframework.web.filter.DelegatingFilterProxy   springSecurityFilterChain /*   org.springframework.web.context.ContextLoaderListener   foo org.springframework.web.servlet.DispatcherServlet 1   foo /   

感谢大家在使用Spring的Java配置时有关springSecurityFilterChain的上述提示。 由于我已经努力应用这些提示来修复我自己的代码中的类似错误,我注意到org.springframework.web.WebApplicationInitializer的Spring文档(由AbstractAnnotationConfigDispatcherServletInitializer实现的接口)具有以下相关的“警告”:

web.xml版本控制

WEB-INF / web.xml和WebApplicationInitializer的使用并不相互排斥; 例如,web.xml可以注册一个servlet,WebApplicationInitializer可以注册另一个。 初始化程序甚至可以通过ServletContext.getServletRegistration(String)等方法修改web.xml中执行的注册。

但是,如果应用程序中存在WEB-INF / web.xml,则其version属性必须设置为“3.0”或更高,否则Servlet容器将忽略ServletContainerInitializer引导。

我指出这一点是因为我注意到你上面提到的web.xml版本仍然是2.5。

我使用Spring 3.2.3和Servlet 3.0。 方法是扩展DelegatingFilterProxy类并将其命名为SpringSecurityFilterChain。

 public class ServiceInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class[] getRootConfigClasses() { return new Class[] { ApplicationConfig.class }; } @Override protected Class[] getServletConfigClasses() { return new Class[] { WebConfig.class }; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } @Override protected Filter[] getServletFilters() { return new Filter[] { new OpenEntityManagerInViewFilter(), new SpringSecurityFilterChain() }; } public class SpringSecurityFilterChain extends DelegatingFilterProxy { } 

}