配置迁移

以下步骤涉及如何配置 HttpSecurityWebSecurity 及相关组件的变化。

使用 Lambda DSL

Lambda DSL 自 Spring Security 5.2 版本起就已存在,它允许使用 lambda 表达式来配置 HTTP 安全。

您可能在 Spring Security 文档或示例中见过这种配置风格。让我们来看看 HTTP 安全的 lambda 配置与之前的配置风格有何不同。

使用 lambda 的配置
@Configuration
@EnableWebSecurity
public class SecurityConfig {

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

        return http.build();
    }
}
不使用 lambda 的等效配置
@Configuration
@EnableWebSecurity
public class SecurityConfig {

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

        return http.build();
    }
}

Lambda DSL 是配置 Spring Security 的首选方式,之前的配置风格将在 Spring Security 7 中失效,届时将强制要求使用 Lambda DSL。这样做主要是出于几个原因:

  • 之前的方式如果不了解返回类型,就不清楚正在配置哪个对象。嵌套越深,就越容易混淆。即使是经验丰富的用户也会认为他们的配置在做一件事,而实际上却在做另一件事。

  • 一致性。许多代码库在这两种风格之间切换,导致不一致,使得理解配置变得困难,并经常导致配置错误。

Lambda DSL 配置技巧

在比较上面的两个示例时,您会注意到一些关键区别

  • 在 Lambda DSL 中,无需使用 .and() 方法链式调用配置选项。调用 lambda 方法后,HttpSecurity 实例会自动返回以进行进一步配置。

  • Customizer.withDefaults() 使用 Spring Security 提供的默认设置启用安全功能。这是 lambda 表达式 it → {} 的快捷方式。

WebFlux 安全

您也可以以类似方式使用 lambda 配置 WebFlux 安全。以下是使用 lambda 的配置示例。

使用 lambda 的 WebFlux 配置
@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 旨在实现以下目标

  • 自动缩进使配置更具可读性。

  • 无需使用 .and() 链式调用配置选项

  • Spring Security DSL 与 Spring Integration 和 Spring Cloud Gateway 等其他 Spring DSL 具有类似的配置风格。

自定义 DSL 使用 .with() 代替 .apply()

在 6.2 版本之前,如果您有自定义 DSL,您会使用 HttpSecurity#apply(…​) 方法将其应用到 HttpSecurity。然而,从 6.2 版本开始,此方法已被弃用,并将在 7.0 版本中移除,因为一旦 .and() 被移除,将无法再使用 .and() 链式调用配置(参见github.com/spring-projects/spring-security/issues/13067)。因此,建议使用新的 .with(…​) 方法。有关如何使用 .with(…​) 的更多信息,请参阅自定义 DSL 部分