覆盖自定义WebSecurityConfigurerAdapter会导致两者都被实例化

时间:2016-11-10 18:40:56

标签: java spring spring-security

这是我的情况:我有一个使用Spring Security的项目。一切都运作良好。

我有这个:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    public AuthenticationFailureHandler getAuthenticationFailureHandler(){
         return new PlainFailureHandler();
    }

    @Override
    protected void configure(HttpSecurity httpSec) throws Exception {
        AuthFilter filter = new AuthFilter(getAuthenticationFailureHandler());
        filter.setAuthenticationManager(authenticationManagerBean());
        httpSec.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class);        
    }

}

到目前为止,一切都很棒。现在,我有第二个项目建立在第一个项目之上。

在其中,我需要覆盖AuthenticationFailureHandler。

我在第二个项目中创建了一个新类,它看起来很相似:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class NewProjectSecurityConfig extends SecurityConfig {

    @Override
    public AuthenticationFailureHandler getAuthenticationFailureHandler() {
        return new NewProjectAuthenticationFailureHandler();
    }
}

现在我的问题是Spring正在实例化它们,导致两个过滤器。我可以添加一个@Order(1)以确保一个在另一个之前完成,但我真正想要的是使用第二个配置,并以某种方式告诉Spring使用它而是的第一个。我还是春天的新人,所以如果我错过了一张更大的图片,我会道歉。项目。我也无法更改第1项,因此我无法删除原始配置并将其复制。

注意:我根本不使用配置文件,这是以编程方式完成的。

1 个答案:

答案 0 :(得分:0)

我认为这是当前设置配置方式的限制。 如果查看WebSecurityConfiguration类,它具有setFilterChainProxySecurityConfigurer方法,该方法注入了AutowiredWebSecurityConfigurersIgnoreParents类解决的所有webSecurityConfigurers。基本上,它会使用所有扩展WebSecurityConfigurerAdapter或实现WebSecurityConfigurer的bean。

现在,该方法会将所有那些配置程序添加到WebSecurity对象中。然后,它是build方法遍历所有那些配置程序(在init()之类的方法中),并且基本上,对每个配置程序执行以下操作:

  1. configurer.init()

  2. configurer.configure()

WebSecurityConfigurerAdapter的Init方法正在执行此操作:

public void init(final WebSecurity web) throws Exception {
        final HttpSecurity http = getHttp();
        web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
            FilterSecurityInterceptor securityInterceptor = http
                    .getSharedObject(FilterSecurityInterceptor.class);
            web.securityInterceptor(securityInterceptor);
        });
}

因此,每个配置程序都会创建并添加自己的过滤器链。

如果通过使用不同的URL来完美地划分您的配置,则可以假设一个配置程序用于“ / api / v1”,另一个配置程序用于“ / api / v2”。

但是,如果您的配置是全局配置或至少相交,那么您将遇到很大麻烦。

让我们说一个定义了csrf.disable(),而另一个没有csrf.disable()。

您的Web请求将通过安全链,如果没有csrf令牌,它将通过第一个链,但不会通过第二个链。因此,有效地取代了配置(一个覆盖/重新定义另一个)的单一配置,而得到了配置(其中两个)作为两个的交集

一种可能的解决方案是扩展现有配置,调用super()并重新定义一些配置,但是同时您需要确保原始配置不在spring所发现的bean列表中。