> ## Documentation Index
> Fetch the complete documentation index at: https://blog.pig4cloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Spring Security 7.0 配置大改，再不升级就晚了！

Spring Security 7.0版本将彻底移除传统的链式配置方式，开发者必须迁移到全新的Lambda DSL配置方式。这是一个重大的突破性变更(Breaking Change)，需要所有使用Spring Security的项目进行相应的代码调整。

## Lambda DSL 配置方式

<img src="https://minio.pigx.vip/oss/202501/1736387660.png" alt="1736387660" />

如上写法被 Spring Security 标记为过时用法，从Spring Security 5.2版本开始引入的Lambda DSL配置方式，将在7.0版本成为**唯一支持**的配置方式。让我们通过实例来了解这种配置方式。

### 传统配置方式的问题

传统配置方式存在以下问题：

1. 使用 `.and()` 方法链接配置块，导致代码嵌套层级深、可读性差
2. 配置块之间的关系不够清晰，容易混淆作用域
3. IDE 难以提供准确的代码补全和类型提示
4. 配置错误只能在运行时才能发现

### Lambda DSL 的优势

相比之下，Lambda DSL 配置方式具有以下优点：

1. 更清晰的层级结构，每个配置块都有明确的作用域
2. 更好的类型安全，编译时就能发现配置错误
3. IDE 可以提供更准确的代码补全
4. 配置逻辑更容易重用和组合
5. 代码更简洁，无需使用 `.and()` 方法

例如，以下是一个典型的 Lambda DSL 配置：

### 新旧配置方式对比

#### 使用 Lambda DSL 的配置方式（推荐）

```java theme={null}
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(authorize -> authorize
                .requestMatchers("/token/**").permitAll()
                .anyRequest().authenticated()
            )
            .formLogin(formLogin -> formLogin
                .loginPage("/login")
                .permitAll()
            )
            .rememberMe(Customizer.withDefaults());

        return http.build();
    }
}
```

#### 传统配置方式（将在7.0中移除）

```java theme={null}
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests()
                .requestMatchers("/token/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .rememberMe();

        return http.build();
    }
}
```

## 为什么要强制使用 Lambda DSL？

Spring Security团队决定在7.0版本中强制使用Lambda DSL，主要基于以下考虑：

1. **更清晰的配置层次**：传统配置方式中，如果不了解返回类型，很难理解正在配置的对象。配置嵌套越深，理解起来就越困难。

2. **一致性**：许多代码库在两种风格之间切换，导致配置不一致，增加了理解难度，容易引起配置错误。

## Lambda DSL 使用技巧

在使用Lambda DSL时，需要注意以下几点：

1. **无需使用.and()**：Lambda DSL配置中不再需要使用`.and()`方法链接配置选项。HttpSecurity实例会在lambda方法调用后自动返回，用于进一步配置。

2. **默认配置简写**：使用`Customizer.withDefaults()`可以启用Spring Security提供的默认配置，这是`it -> {}`lambda表达式的简写形式。

## WebFlux 安全配置

WebFlux的安全配置同样支持Lambda DSL，示例如下：

```java theme={null}
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http
            .authorizeExchange(exchanges -> exchanges
                .pathMatchers("/blog/**").permitAll()
                .anyExchange().authenticated()
            )
            .httpBasic(Customizer.withDefaults())
            .formLogin(formLogin -> formLogin
                .loginPage("/login")
            );

        return http.build();
    }
}
```

## Lambda DSL 的设计目标

Lambda DSL的设计目标包括：

1. **自动缩进**：通过IDE的自动缩进功能，使配置更易读。
2. **移除.and()**：不再需要使用`.and()`方法链接配置。
3. **统一风格**：与Spring Integration和Spring Cloud Gateway等其他Spring DSL保持一致的配置风格。

## 自定义DSL的变更

从6.2版本开始，对于自定义DSL：

* 废弃：`HttpSecurity#apply(…)`方法
* 推荐：使用新的`.with(…)`方法

这一变更是由于在7.0版本中将完全移除`.and()`方法。

### 如何创建自定义DSL

在Spring Security中，你可以创建自己的自定义DSL。以下是一个完整的示例：

```java theme={null}
public class MyCustomDsl extends AbstractHttpConfigurer<MyCustomDsl, HttpSecurity> {
    private boolean flag;

    @Override
    public void init(HttpSecurity http) throws Exception {
        // 在init方法中添加其他配置器
        // 例如禁用CSRF
        http.csrf().disable();
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        ApplicationContext context = http.getSharedObject(ApplicationContext.class);

        // 从ApplicationContext中获取Bean，也可以直接创建新实例
        MyFilter myFilter = context.getBean(MyFilter.class);
        myFilter.setFlag(flag);
        http.addFilterBefore(myFilter, UsernamePasswordAuthenticationFilter.class);
    }

    public MyCustomDsl flag(boolean value) {
        this.flag = value;
        return this;
    }

    public static MyCustomDsl customDsl() {
        return new MyCustomDsl();
    }
}
```

这实际上就是Spring Security内部实现`HttpSecurity.authorizeHttpRequests()`等方法的方式。

### 使用自定义DSL

在配置类中，你可以这样使用自定义DSL：

```java theme={null}
@Configuration
@EnableWebSecurity
public class Config {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .with(MyCustomDsl.customDsl(), (dsl) -> dsl
                .flag(true)
            )
            // ... 其他配置
        return http.build();
    }
}
```

在创建自定义DSL时，请注意以下几点：

1. 继承 `AbstractHttpConfigurer` 类，它提供了必要的基础设施
2. 在 `init` 方法中添加其他配置器
3. 在 `configure` 方法中实现具体的安全配置逻辑
4. 提供流式API以保持配置风格的一致性
5. 使用静态工厂方法来创建DSL实例

## 总结

Spring Security 7.0的配置变更主要围绕Lambda DSL展开，这种变更将带来更清晰、一致的配置体验。建议开发团队及早开始相关迁移工作，以确保顺利过渡到新版本。
