为什么引入springsecurity的依赖后,会自动创建了过滤器链

spring.factories.imports 文件

在 Spring Boot 2.7 之前,自动配置类的注册是通过 META-INF/spring.factories 文件完成的,其中包含类似这样的条目:

为了提高性能、模块化和可读性,Spring Boot 2.7 引入了新的、专用的 .imports 文件机制来替代 spring.factories 中的自动配置注册。

org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件是一个纯文本文件,每行包含一个自动配置类的全限定类名(Fully Qualified Class Name)

  • 每行一个类名
  • 支持注释 :以 # 开头的行被视为注释,可以用来说明或临时禁用某个配置。
  • 语义清晰:文件名本身就说明了它的用途------注册自动配置导入。

工作原理

  1. 启动扫描 :当你的 Spring Boot 应用程序启动时,SpringApplication 会扫描所有 classpath 下的 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件。
  2. 读取类名:它会读取这些文件中的每一行,获取自动配置类的全限定名。
  3. 条件化加载 :对于每个列出的类,Spring Boot 会检查其上的条件注解(如 @ConditionalOnClass, @ConditionalOnMissingBean, @ConditionalOnProperty 等)。
  4. 注册 Bean :如果所有条件都满足,该自动配置类就会被加载,其中定义的 @Bean 方法会被执行,相关的组件(如数据源、模板引擎、安全配置等)就会自动注册到 Spring 应用上下文中。

SecurityAutoConfiguration

当我们引入了security相关依赖的时候,SecurityAutoConfiguration自动配置类开始发挥作用

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
ruby 复制代码
@Import({ SpringBootWebSecurityConfiguration.class, SecurityDataConfiguration.class })
public class SecurityAutoConfiguration {

}

SecurityAutoConfiguration中引入了SpringBootWebSecurityConfiguration配置类

less 复制代码
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
class SpringBootWebSecurityConfiguration {

  
   @Configuration(proxyBeanMethods = false)
   @ConditionalOnDefaultWebSecurity
   static class SecurityFilterChainConfiguration {
        
      //配置默认的过滤器链条  
      @Bean
      @Order(SecurityProperties.BASIC_AUTH_ORDER)
      SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
         http.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());
         http.formLogin(withDefaults());
         http.httpBasic(withDefaults());
         return http.build();
      }

   }

   // 启用@EnableWebSecurity注解
   @Configuration(proxyBeanMethods = false)
   @ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN)
   @ConditionalOnClass(EnableWebSecurity.class)
   @EnableWebSecurity
   static class WebSecurityEnablerConfiguration {

   }

}

SpringBootWebSecurityConfiguration做了两件事相对重要 一是创建了默认的过滤器链,二是使用了@EnableWebSecurity注解 这就是为什么我们只引入了jar包 springsecurity就可以通过默认的过滤器链来保护我们的资源,同时我们也可以看出开发者如果忘记了使用@EnableWebSecurity注解也没关系,框架会自动帮我们开启。

默认过滤器链

从上面的代码我们可以看出 SecurityFilterChainConfiguration将SecurityFilterChain实例注入到容器中,但前提是@ConditionalOnDefaultWebSecurity这个注解需要生效

css 复制代码
@ConditionalOnDefaultWebSecurity

@ConditionalOnDefaultWebSecurity本质上是@Conditional注解

less 复制代码
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(DefaultWebSecurityCondition.class)
public @interface ConditionalOnDefaultWebSecurity {

}

@Conditional(DefaultWebSecurityCondition.class) 这个是spring的条件化配置,意思是只有当 DefaultWebSecurityCondition 这个条件被判定为 true 时,被它标注的类或方法才应该被注册到 Spring 容器中(即生效);否则,就跳过它。

@Conditional注解要求传入一个实现了Condition接口的类作为参数,DefaultWebSecurityCondition实现了这个接口

  • 在 Spring 应用上下文启动过程中,当遇到被 @Conditional 标注的元素时,Spring 会实例化你指定的 Condition 类(这里是 DefaultWebSecurityCondition),并调用其 matches() 方法。
java 复制代码
@FunctionalInterface
public interface Condition {
   boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

这个类的主要作用是: 当内部类的所有的 .@Conditional 注解都成立的时候,才会注入该 Bean

scala 复制代码
class DefaultWebSecurityCondition extends AllNestedConditions {

   DefaultWebSecurityCondition() {
      super(ConfigurationPhase.REGISTER_BEAN);
   }

   //  **作用**:`@ConditionalOnClass` 注解检查类路径(classpath)上是否存在指定的类。
   //**逻辑**:只有当 `SecurityFilterChain.class` 和 `HttpSecurity.class` 这两个类**都存在于**类路径上时,这个条件才算通过
   @ConditionalOnClass({ SecurityFilterChain.class, HttpSecurity.class })
   static class Classes {

   }

   // 只有当当前 Spring 容器中**没有**类型为 `SecurityFilterChain` 的 Bean 时,这个条件才算通过
   @ConditionalOnMissingBean({ SecurityFilterChain.class })
   static class Beans {

   }

}

所以springsecurity自动创建过滤器链的满足的条件是:1 类需要存在 2.用户没有手动的配置SecurityFilterChain。

目的 :这是实现"自定义优先 "(Opinionated Defaults)的关键。Spring Boot 的理念是,如果开发者没有进行任何安全配置,它就提供一个安全的默认配置(通常是一个简单的登录表单)。但如果开发者自己定义了一个 SecurityFilterChain Bean 来配置自定义的安全规则(比如 OAuth2、JWT、特定的 URL 权限等),那么 Spring Boot 就应该自动禁用 其默认的安全配置,避免冲突。这个条件确保了只有在用户没有提供自己的安全配置时,才会应用默认配置

EnableWebSecurity

上面说自动配置类WebSecurityEnablerConfiguration帮我开启EnableWebSecurity注解, 但是有个前提是

@ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN) @ConditionalOnClass(EnableWebSecurity.class) 这两个条件得同时生效 1是类路径中要存在EnableWebSecurity这个类 2是** Spring 容器中不存在名为 "springSecurityFilterChain" 的 Bean**

这么做的目的是:当 @EnableWebSecurity 注解被处理时,它会创建一个名为 springSecurityFilterChainFilterChainProxy Bean,这个 Bean 是整个 Spring Security 过滤器链的入口,如果用户正确地使用了 @EnableWebSecurity @EnableWebSecurity 注解本身就会触发创建 springSecurityFilterChain Bean。 同样,WebSecurityEnablerConfiguration 会因为该 Bean 已存在而被禁用,防止了 @EnableWebSecurity 被应用两次。

相关推荐
程序员cxuan14 小时前
速度太快了!本地可以跑 DeepSeek-V4-Flash 了
人工智能·后端·程序员
阿祖zu15 小时前
芝士就是力量!开源私有化部署与 GitHub 双向同步的个人知识笔记 App
前端·后端·ios
不才不才不不才15 小时前
Spring 源码系列(16): doDispatch 全流程——一次请求的主干链路
java·后端·spring
IT_陈寒15 小时前
SpringBoot自动配置失效?这个隐藏配置坑了我一整晚
前端·人工智能·后端
搜狐技术产品小编202315 小时前
告别“黑盒”与误判:如何用“多智能体对抗辩论”重构内容安全审核系统
后端·多agent
DantyWei16 小时前
controller注册及调用时机
后端
edwarddamon16 小时前
Spring Cloud 配置热更新与 Bean 代理机制梳理
java·后端
码事漫谈16 小时前
我用 Seed Evolving 做了个 AI 小说写作工具
后端
Raas10016 小时前
MAIGateway,魔芋企业级AI网关的FinAPI成本竞争力设计
java·后端·网关·api网关·魔芋ai·finapi·mai gateway
计算机魔术师17 小时前
传统基础架构 - 微服务
大数据·后端·微服务·架构·开发工具·编程语言