如何重现与 Spring Security 相关的 bean 加载顺序问题?

问题描述 投票:0回答:1

我们正在为 Spring Boot 项目提供公司内部库。该库包含两个过滤器,

SpringMvcFilter
SpringSecurityFilter

SpringMvcFilter
应默认加载。配置 Spring Security 时应加载
SpringSecurityFilter
,但随后应停用
SpringMvcFilter
SpringMvcFilter
的配置如下:

@AutoConfiguration
public class SpringMvcConfig {

    @Bean
    @ConditionalOnMissingBean(name = {"springSecurityFilterChain"})
    public Filter springMvcFilter() {
        // implementation
    }
}

SpringSecurityFilter
配置如下:

public class SpringSecurityConfigurer extends AbstractHttpConfigurer<SpringSecurityConfigurer, HttpSecurity> {

    @Override
    public void configure(HttpSecurity builder) {
        builder.addFilterBefore(new SpringSecurityFilter(), BasicAuthenticationFilter.class);
    }
}

配置 Spring Security 时,

@ConditionalOnMissingBean
注解应防止加载
SpringMvcFilter
。这适用于除一个客户之外的所有客户,即对于所述客户,两个过滤器均已加载并处于活动状态,并且我无法重现此问题。

我设置了一个 Spring Boot 项目 (2.7.16),配置了 Spring Security,并向公开三个 bean 的库添加了依赖项:

@AutoConfiguration
public class CoolReuseBeans {

    @Bean("coolReuseIntBean")
    @ConditionalOnMissingBean(name = {"springSecurityFilterChain"})
    public Integer beanInt() {
        return 5;
    }

    @Bean("coolReuseStringBean")
    @ConditionalOnBean(name = {"springSecurityFilterChain"})
    public String beanString() {
        return "5";
    }

    @Bean("coolReuseBooleanBean")
    public Boolean beanBoolean() {
        return true;
    }
}

Spring Security 配置非常简单:

@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(requests -> requests
                        .requestMatchers(new AntPathRequestMatcher("/")).permitAll()
                        .anyRequest().authenticated());
        return http.build();
    }
}

应用程序在启动时打印是否已找到相应的 bean:

@SpringBootApplication
public class Application {
    private  static ConfigurableApplicationContext applicationContext;

    public static void main(String[] args) {
         applicationContext = SpringApplication.run(Application.class, args);
        hasBean("springSecurityFilterChain");
        hasBean("coolReuseIntBean");
        hasBean("coolReuseStringBean");
        hasBean("coolReuseBooleanBean");
    }

    private static void hasBean(String name) {
        String[] allBeanNames = applicationContext.getBeanDefinitionNames();
        System.out.println(String.format("Did find %s? %s", name, Arrays.stream(allBeanNames).anyMatch(x -> x.equals(name))));
    }
}

启动应用程序时,会记录以下内容:

253: DEBUG 36231 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'springSecurityFilterChain'

366: DEBUG 36231 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'com.example.beans.CoolReuseBeans'
367: DEBUG 36231 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'coolReuseStringBean'
368: DEBUG 36231 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'coolReuseBooleanBean'

CoolReuseBeans#beanString matched:
      - @ConditionalOnBean (names: springSecurityFilterChain; SearchStrategy: all) found bean 'springSecurityFilterChain' (OnBeanCondition)

CoolReuseBeans#beanInt:
      Did not match:
         - @ConditionalOnMissingBean (names: springSecurityFilterChain; SearchStrategy: all) found beans named springSecurityFilterChain (OnBeanCondition)


Did find springSecurityFilterChain? true
Did find coolReuseIntBean? false
Did find coolReuseStringBean? true
Did find coolReuseBooleanBean? true

这仍然是我所期望的。由于配置了 Spring Security 并加载了

springSecurityFilterChain
bean,因此会加载依赖于它的 bean,而依赖于
springSecurityFilterChain
不存在的 bean 则不会加载。

当我注释掉

@EnableWebSecurity
注释并启动应用程序时,将记录以下内容:

366: DEBUG 37070 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'com.example.beans.CoolReuseBeans'
367: DEBUG 37070 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'coolReuseIntBean'
368: DEBUG 37070 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'coolReuseBooleanBean'

385: DEBUG 37070 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'springSecurityFilterChain'

CoolReuseBeans#beanInt matched:
      - @ConditionalOnMissingBean (names: springSecurityFilterChain; SearchStrategy: all) did not find any beans (OnBeanCondition)

CoolReuseBeans#beanString:
      Did not match:
         - @ConditionalOnBean (names: springSecurityFilterChain; SearchStrategy: all) did not find any beans named springSecurityFilterChain (OnBeanCondition)

Did find springSecurityFilterChain? true
Did find coolReuseIntBean? true
Did find coolReuseStringBean? false
Did find coolReuseBooleanBean? true

对于从我的库加载哪些 bean,这也按预期工作。然而,让我困惑的一件事是,尽管配置了 Spring Security,但

springSecurityFilterChain
bean 显然仍在加载,尽管是在其他 bean 之后(这可能就是结果仍然正确的原因)。

除此之外,我不知道如何重现该问题。可以解释一位客户遇到的问题的行为是,在处理包含

springSecurityFilterChain
bean 的
@AutoConfiguration
后加载
SpringMvcFilter
。但是,我无法找到一种方法来实现这一点。它还与我对
@AutoConfiguration
的理解相矛盾,即这些是在 Springs bean 加载代码的最后一点处理的。

如果有人知道这里发生了什么或者我还可以尝试重现什么,我很高兴听到您的意见!

spring-boot spring-security dependency-injection javabeans
1个回答
0
投票

指定在SecurityAutoConfiguration后面配置CoolReuseBeans,

@AutoConfiguration(after=SecurityAutoConfiguration.class) 
public class CoolReuseBeans { 
} 
© www.soinside.com 2019 - 2024. All rights reserved.