How to implement Spring Security 4 with both XML a

2020-02-29 01:39发布

问题:

I am trying to implement Spring-Security 4 into my Spring MVC web and rest app. I added 2 classes to enable Spring Security the java config way. I still want to hold onto my web.xml and not change the entire project to use java config. As soon as I do that, I get the following error:

29-May-2015 08:47:12.826 SEVERE [localhost-startStop-1]  
org.apache.catalina.core.StandardContext.filterStart Exception starting   
filter springSecurityFilterChain
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean   
named 'springSecurityFilterChain' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.
getBeanDefinition(DefaultListableBeanFactory.java:687)

As you can see, it says that the springSecurityFilterChain cannot be recognized. This is of course supposed to be enabled by the @EnableWebSecurity as you see below:

Classes used for Spring Security:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
  auth.inMemoryAuthentication().withUser("abc").password("123456").roles("USER");
  auth.inMemoryAuthentication().withUser("admin").password("123456").roles("ADMIN");
  auth.inMemoryAuthentication().withUser("dba").password("123456").roles("DBA");
}

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

  http.authorizeRequests()
    .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
    .antMatchers("/dba/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_DBA')")
    .and().formLogin();

    }
}

public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
   //do nothing
}

The weird thing is if I add the springSecurityFilterChain to my web.xml, at runtime it complains and says there is a duplicate springSecurityFilterChain. I noticed that ultimately in the Java config, they do this:

public class MvcWebApplicationInitializer extends
    AbstractAnnotationConfigDispatcherServletInitializer {

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

Where they register the SecurityConfig with the Java config for the MvcWebApp. This basically makes it part of the servlet context I believe.

All in all, how can I have my springSecurityFilterChain recognized? Do I need to register my SecurityConfig class in web.xml or the existing application context?

I think this may be the first problem area:

public class SecurityWebApplicationInitializer
  extends AbstractSecurityWebApplicationInitializer {

}

The spring docs say:

Instead, we should register Spring Security with the existing ApplicationContext. For example, if we were using Spring MVC our SecurityWebApplicationInitializer.

Can this mean in my case, I can take SecurityConfig and should make it a bean? Or is it not already a bean because it is dicoverable through @Configuration?

How can I make SecurityConfig recognized via XML while using the new Java config as well?

回答1:

Thanks to ArunM, I revisited my issue and now have an XML and Java config combination. Spring MVC and the web app does use web.xml and default-servlet.xml PLUS a java config app class that imports Spring Security.

@Configuration
@Import({ SecurityConfig.class})
@ImportResource( {"classpath:web-context.xml",
   "classpath:service-context.xml","classpath:data-context.xml"})
public class AppConfig {
   public AppConfig() {
      super();
   }
}

I use the @Import annotation to import the Spring Security SecurityConfig class.

I also do my contextConfigLocation scanning for all my context files via annotation: @ImportResource.

The trick was not to load SecurityConfig via the contextConfigLocation BUT create an AppConfig class that sets up the app context by including everything in it together.



回答2:

Assuming what you want is to get Spring Security Java Config working with only 2 classes SecurityConfig and SecurityWebApplicationInitializer, you need to do the following to get it working. Please note that I am assuming that your spring mvc configuration is still XML. Please note that com.mkyong.web.config package will have the SecurityConfigclass. This will ensure that the web context will have your security configuration available.

Web.xml as follows

<context-param>
          <param-name>contextClass</param-name>
          <param-value>
              org.springframework.web.context.support.AnnotationConfigWebApplicationContext
          </param-value>
      </context-param>
      <context-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>com.mkyong.web.config</param-value>
      </context-param>

   <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>


回答3:

Add the following line in your spring-context.xml:

<!-- to activate annotations in beans already registered in the application context -->
<context:annotation-config />

and then can add the bean definition for the security config.

<bean name="SecurityConfig" class="com.config.security.SecurityConfig" />