Migrate Application from Spring Security 5 to Spring Security 6/Spring Boot 3 – 将应用程序从 Spring Security 5 迁移到 Spring Security 6/Spring Boot 3

最后修改: 2024年 3月 10日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Spring Security 6 comes with several major changes, including the removal of classes, and deprecated methods, and the introduction of new methods.

Spring Security 6 有几处重大变化,包括删除了一些类和已废弃的方法,并引入了一些新方法。

Migrating from Spring Security 5 to Spring Security 6 can be done incrementally without breaking the existing code base. Also, we can use third-party plugins like OpenRewrite to facilitate migration to the latest version.

从 Spring Security 5 迁移到 Spring Security 6 可以在不破坏现有代码库的情况下逐步完成。此外,我们还可以使用第三方插件,如 OpenRewrite 来促进向最新版本的迁移。

In this tutorial, we’ll learn how to migrate an existing application using Spring Security 5 to Spring Security 6. We’ll replace deprecated methods and utilize lambda DSL to simplify configuration. Also, we’ll utilize OpenRewrite to make migration faster.

在本教程中,我们将学习如何将使用 Spring Security 5 的现有应用程序迁移到 Spring Security 6。我们将替换过时的方法,并利用 lambda DSL 简化配置。此外,我们还将利用 OpenRewrite 加快迁移速度。

2. Spring Security and Spring Boot Version

2.Spring Security 和 Spring Boot 版本

Spring Boot is based on the Spring framework, and the versions of Spring Boot use the latest version of the Spring framework. Spring Boot 2 defaults to Spring Security 5, while Spring Boot 3 uses Spring Security 6.

Spring Boot 基于 Spring 框架,Spring Boot 的各个版本都使用最新版本的 Spring 框架。Spring Boot 2 默认使用 Spring Security 5,而 Spring Boot 3 使用 Spring Security 6。

To use Spring Security in a Spring Boot application, we always add the spring-boot-starter-security dependency to the pom.xml.

要在 Spring Boot 应用程序中使用 Spring Security,我们必须将 spring-boot-starter-security 依赖关系添加到 pom.xml. 中。

However, we can override the default Spring Security version by specifying a desired version in the properties section of pom.xml:

不过,我们可以在 pom.xml 的 properties 部分中指定所需的版本,从而覆盖默认的 Spring Security 版本:

<properties>
    <spring-security.version>5.8.9</spring-security.version>
</properties>

Here, we specify that we are using Spring Security 5.8.9 in our project, overwriting the default version.

在这里,我们指定在项目中使用 Spring Security 5.8.9,覆盖默认版本。

Notably, we can also use Spring Security 6 in Spring Boot 2 by overriding the default version in the properties section.

值得注意的是,通过覆盖 properties 部分中的默认版本,我们也可以在 Spring Boot 2 中使用 Spring Security 6。

3. What’s New in Spring Security 6

3.Spring Security 6 的新功能

Spring Security 6 introduces several feature updates to improve security and robustness. It now requires at least Java version 17 and uses the jakarta namespace.

Spring Security 6 引入了多项功能更新,以提高安全性和健壮性。它现在至少需要 Java 17 版本,并使用 jakarta 命名空间。

One of the major changes is the removal of WebSecurityConfigurerAdapter in favor of component-based security configuration.

其中一项主要更改是移除 WebSecurityConfigurerAdapter 以支持基于组件的安全配置

Also, the authorizeRequests() is removed and replaced with authorizeHttpRequests() to define authorization rules.

此外,删除了 authorizeRequests() 并代之以 authorizeHttpRequests() 来定义授权规则。

Furthermore, it introduces methods like requestMatcher() and securityMatcher() to replace antMatcher() and mvcMatcher() for configuring security for request resources. The requestMatcher() method is more secure because it chooses the appropriate RequestMatcher implementation for request configuration.

此外,它还引入了 requestMatcher() securityMatcher() 等方法,以取代 antMatcher() 和 mvcMatcher() 来配置请求资源的安全性requestMatcher()方法更安全,因为它会为请求配置选择适当的RequestMatcher实现。

Other deprecated methods like cors() and csrf() now have functional style alternatives.

其他已废弃的方法,如 cors()csrf() 现在有了函数式的替代方法。

4. Project Setup

4.项目设置

To begin, let’s bootstrap a Spring Boot 2.7.5 project by adding spring-boot-starter-web and spring-boot-starter-security to the pom.xml:

首先,让我们通过在 pom.xml 中添加 spring-boot-starter-webspring-boot-starter-security 来引导 Spring Boot 2.7.5 项目:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.7.5</version>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    <version>2.7.5</version>
</dependency>

The spring-boot-starter-security dependency uses the Spring Security 5.

spring-boot-starter-security 依赖关系使用 Spring Security 5。

Next, let’s create a class named WebSecurityConfig:

接下来,让我们创建一个名为 WebSecurityConfig 的类:

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
}

Here, we annotate the class with @EnableWebSecurity to initiate the process of configuring security for web requests. Also, we enable method-level authorization. Next, the class extends the WebSecurityConfigurerAdapter class to provide various security configuration methods.

在此,我们用 @EnableWebSecurity 对该类进行注解,以启动为 Web 请求配置安全性的过程。此外,我们还启用了方法级授权。接下来,该类将扩展 WebSecurityConfigurerAdapter 类,以提供各种安全配置方法。

Furthermore, let’s define an in-memory user for authentication:

此外,让我们定义一个内存用户用于身份验证:

@Override
void configure(AuthenticationManagerBuilder auth) throws Exception {
    UserDetails user = User.withDefaultPasswordEncoder()
      .username("Admin")
      .password("password")
      .roles("ADMIN")
      .build();
    auth.inMemoryAuthentication().withUser(user);
}

In the method above, we create an in-memory user by overriding the default configuration.

在上述方法中,我们通过覆盖默认配置创建了一个内存用户。

Moving on, let’s exclude static resources from the security by overriding the configure(WebSecurity web) method:

接下来,让我们通过重载 configure(WebSecurity web) 方法,将静态资源排除在安全性之外:

@Override
void configure(WebSecurity web) {
    web.ignoring().antMatchers("/js/**", "/css/**");
}

Finally, let’s create HttpSecurity by overriding the configure(HttpSecurity http) method:

最后,让我们通过覆盖 configure(HttpSecurity http) 方法来创建 HttpSecurity

@Override
void configure(HttpSecurity http) throws Exception {
    http
      .authorizeRequests()
      .antMatchers("/").permitAll()
      .anyRequest().authenticated()
      .and()
      .formLogin()
      .and()
      .httpBasic();
}

Notably, this setup showcases typical Spring Security 5 configuration. In the subsequent section, we’ll migrate this code to Spring Security 6.

值得注意的是,该设置展示了典型的 Spring Security 5 配置。在接下来的章节中,我们将把这些代码移植到 Spring Security 6。

5. Migrating Project to Spring Security 6

5.将项目迁移到 Spring Security 6

Spring recommends an incremental migration approach to prevent breaking existing code when updating to Spring Security 6. Before upgrading to Spring Security 6, we can first upgrade our Spring Boot application to Spring Security 5.8.5 and update the code to use new features. Migrating to 5.8.5 prepares us for expected changes in version 6.

Spring 建议采用增量迁移方法,以防止在升级到 Spring Security 6 时破坏现有代码。在升级到 Spring Security 6 之前,我们可以先将 Spring Boot 应用程序升级到 Spring Security 5.8.5,并更新代码以使用新功能。迁移到 5.8.5 可让我们为版本 6 中的预期更改做好准备。

While migrating incrementally, our IDE can warn us of deprecated features. This aids the incremental update process.

在增量迁移过程中,我们的集成开发环境可以提醒我们注意已废弃的功能。这有助于增量更新过程。

For simplicity, let’s migrate the sample project straight to Spring Security 6 by updating the application to use Spring Boot version 3.2.2. In a case where the application uses Spring Boot version 2, we can specify Spring Security 6 in the properties section.

为简单起见,让我们通过更新应用程序使其使用 Spring Boot 3.2.2 版本,将示例项目直接迁移到 Spring Security 6。在应用程序使用 Spring Boot 版本 2 的情况下,我们可以在 properties 部分指定 Spring Security 6。

To begin the migration process, let’s modify the pom.xml to use the latest Spring Boot version:

要开始迁移过程,让我们修改 pom.xml 以使用最新的 Spring Boot 版本:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>3.2.2</version>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    <version>3.2.2</version>
</dependency>

In the initial setup, we use Spring Boot 2.7.5, which uses Spring Security 5 under the hood.

在初始设置中,我们使用 Spring Boot 2.7.5,它在引擎盖下使用 Spring Security 5。

Notably, the minimum Java version for Spring Boot 3 is Java 17.

值得注意的是,Spring Boot 3 的最低 Java 版本是 Java 17。

In the subsequent sub-sections, we’ll refactor the existing code to use Spring Security 6.

在随后的小节中,我们将重构现有代码以使用 Spring Security 6。

5.1. @Configuration Annotation

5.1.@配置注释

Before Spring Security 6, the @Configuration annotation is part of @EnableWebSecurity, but with the latest update, we have to annotate our security configuration with the @Configuration annotation:

在 Spring Security 6 之前,@Configuration注解是@EnableWebSecurity的一部分,但在最新更新后,我们必须使用@Configuration注解来注解我们的安全配置:

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
}

Here, we introduce the @Configuration annotation to the existing code base because it’s no longer part of the @EnableWebSecurity annotation. Also, the annotation is no longer part of @EnableMethodSecurity, @EnableWebFluxSecurity, or @EnableGlobalMethodSecurity annotations.

在此,我们将 @Configuration注解引入到现有代码库中,因为它不再是@EnableWebSecurity注解的一部分。此外,该注解也不再是 @EnableMethodSecurity@EnableWebFluxSecurity@EnableGlobalMethodSecurity 注释的一部分。

Additionally, @EnableGlobalMethodSecurity is marked for deprecation and to be replaced by @EnableMethodSecurity. By default, it enables Spring’s pre-post annotations. Hence, we introduce @EnableMethodSecurity to provide authorization at the method level

此外,@EnableGlobalMethodSecurity 已被标记为过时,并将被 @EnableMethodSecurity 所取代。默认情况下,它会启用 Spring 的前置注解。因此,我们引入了 @EnableMethodSecurity,以提供方法级别的授权

5.2. WebSecurityConfigurerAdapter

5.2.WebSecurityConfigurerAdapter</em

The latest update removes the WebSecurityConfigurerAdapter class and adopts component-based configuration:

最新更新删除了 WebSecurityConfigurerAdapter 类,并采用了基于组件的配置:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
}

Here, we remove the WebSecurityConfigurerAdapter, and this eliminates overriding methods for security configuration. Instead, we can register a bean for security configuration. We can register the WebSecurityCustomizer bean to configure web security, the SecurityFilterChain bean to configure HTTP security, the InMemoryUserDetails bean to register custom users, etc.

在这里,我们删除了 WebSecurityConfigurerAdapter,从而消除了对安全配置方法的覆盖。相反,我们可以为安全配置注册一个 Bean。我们可以注册 WebSecurityCustomizer Bean 来配置 Web 安全性,注册 SecurityFilterChain Bean 来配置 HTTP 安全性,注册 InMemoryUserDetails Bean 来注册自定义用户等。

5.3. WebSecurityCustomizer Bean

5.3.WebSecurityCustomizer Bean

Let’s modify the method that excludes static resources by publishing a WebSecurityCustomizer bean:

让我们通过发布 WebSecurityCustomizer Bean 来修改排除静态资源的方法:

@Bean
WebSecurityCustomizer webSecurityCustomizer() {
   return (web) -> web.ignoring().requestMatchers("/js/**", "/css/**");
}

The WebSecurityCustomizer interface replaces configure(Websecurity web) from the WebSecurityConfigurerAdapter interface.

WebSecurityCustomizer 接口取代了 WebSecurityConfigurerAdapter 接口中的configure(Websecurity web) 接口。

5.4. AuthenticationManager Bean

5.4.身份验证管理器 Bean

In the earlier section, we created an in-memory user by overriding configure(AuthenticationManagerBuilder auth) from the WebSecurityConfigurerAdapter.

在前面的章节中,我们通过覆盖 WebSecurityConfigurerAdapter 中的 configure(AuthenticationManagerBuilder auth) 来创建内存用户。

Let’s refactor the authentication credentials logic by registering InMemoryUserDetailsManager bean instead:

让我们通过注册 InMemoryUserDetailsManager Beanager 来重构身份验证凭据逻辑:

@Bean
InMemoryUserDetailsManager userDetailsService() {
    UserDetails user = User.withDefaultPasswordEncoder()
      .username("Admin")
      .password("admin")
      .roles("USER")
      .build();

    return new InMemoryUserDetailsManager(user);
}

Here, we define an in-memory user with a USER role to provide role-based authorization.

在这里,我们定义了一个具有 USER 角色的内存用户,以提供基于角色的授权。

5.5. HTTP Security Configuration

5.5.HTTP 安全配置

In the previous Spring Security version, we configure HttpSecurity by overriding the configure method from the WebSecurityConfigurer class. Since it’s removed in the latest version, let’s register the SecurityFilterChain bean for HTTP security configuration:

在以前的 Spring Security 版本中,我们通过覆盖 WebSecurityConfigurer 类中的 configure 方法来配置 HttpSecurity 。由于它已在最新版本中移除,因此让我们注册用于 HTTP 安全配置的 SecurityFilterChain Bean:

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
      .authorizeHttpRequests(
          request -> request
            .requestMatchers("/").permitAll()
            .anyRequest().authenticated()
      )
      .formLogin(Customizer.withDefaults())
      .httpBasic(Customizer.withDefaults());
   return http.build();
}

In the code above, we replace the authorizeRequest() method with authorizeHttpRequests(). The new method uses AuthorizationManager API, which simplifies reuse and customization.

在上面的代码中,我们将 authorizeRequest() 方法替换为 authorizeHttpRequests()。新方法使用了 AuthorizationManager API,从而简化了重用和定制。

Additionally, it improves performance by delaying authentication lookup. Authentication lookup occurs only when a request requires authorization.

此外,它还能通过延迟身份验证查询来提高性能。只有当请求需要授权时,才会进行身份验证查询。

When we don’t have a customized rule, we use the Customizer.withDefaults() method to use the default configuration.

如果没有自定义规则,我们将使用 Customizer.withDefaults() 方法来使用默认配置。

Additionally, we use requestMatchers() instead of antMatcher() or mvcMatcher() to secure resources.

此外,我们使用 requestMatchers() 而不是 antMatcher()mvcMatcher() 来确保资源安全。

5.6. RequestCache

5.6 请求缓存</em

The request cache helps save user requests when they are required to authenticate and redirect users to the request once they successfully authenticate. Before Spring Security 6, RequestCache checks on every incoming request to see if there are any saved requests to redirect to. This read the HttpSession on every RequestCache.

请求缓存有助于在需要进行身份验证时保存用户请求,并在用户成功通过身份验证后将其重定向到请求。在 Spring Security 6 之前,RequestCache 会对每个传入请求进行检查,以查看是否有任何已保存的请求要重定向到。这会读取每个 RequestCache 上的 HttpSession

However, in Spring Security 6, the request cache only checks if the request contains a special parameter name “continue“. This improves performance and prevents unnecessary reading of HttpSession.

不过,在 Spring Security 6 中,请求缓存只检查请求是否包含特殊参数”continue“。这不仅提高了性能,还防止了对 HttpSession 的不必要读取。

6. Using OpenRewrite

6.使用 OpenRewrite

Moreover, we can use third-party tools like OpenRewrite to migrate an existing Spring Boot application to Spring Boot 3. Since Spring Boot 3 uses Spring Security 6, it also migrates the security configuration to version 6.

此外,我们还可以使用 OpenRewrite 等第三方工具将现有的 Spring Boot 应用程序迁移到 Spring Boot 3。由于 Spring Boot 3 使用 Spring Security 6,因此它也会将安全配置迁移到版本 6。

To use OpenRewrite, we can add a plugin to the pom.xml:

要使用 OpenRewrite,我们可以在 pom.xml 中添加 插件

<plugin>
    <groupId>org.openrewrite.maven</groupId>
    <artifactId>rewrite-maven-plugin</artifactId>
    <version>5.23.1</version>
    <configuration>
        <activeRecipes>
            <recipe>org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_0</recipe>
        </activeRecipes>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>org.openrewrite.recipe</groupId>
            <artifactId>rewrite-spring</artifactId>
            <version>5.5.0</version>
        </dependency>
    </dependencies>
</plugin>

Here, we specify upgrading to Spring Boot version 3 through the recipe property. OpenRewrite has a lot of recipes to choose from for upgrading a Java project.

在这里,我们通过 recipe 属性指定升级到 Spring Boot 版本 3。OpenRewrite 有很多用于升级 Java 项目的配方可供选择。

Finally, let’s run the migration command:

最后,让我们运行迁移命令:

$ mvn rewrite:run

The command above migrates the project to Spring Boot 3, including the security configuration. However, OpenRewrite currently doesn’t use lambda DSL for the migrated security configuration. Of course, this is likely to change in future releases.

上述命令将项目迁移到 Spring Boot 3,包括安全配置。不过,OpenRewrite 目前没有为迁移的安全配置使用 lambda DSL。当然,这可能会在未来的版本中有所改变。

7. Conclusion

7.结论

In this article, we saw a step-by-step guide for migrating an existing code base using Spring Security 5 to Spring Security 6 by replacing deprecated classes and methods. Additionally, we saw how to use a third-party plugin to automate the migration. As always, the full source code for the examples is available over on GitHub.

在本文中,我们将逐步介绍如何通过替换已废弃的类和方法,将使用 Spring Security 5 的现有代码库迁移到 Spring Security 6。此外,我们还了解了如何使用第三方插件自动完成迁移。一如既往,示例的完整源代码可在 GitHub 上获取。