將應用程式從 Spring Security 5 移轉到 Spring Security 6/Spring Boot 3
1. 概述
Spring Security 6 帶來了幾項重大更改,包括刪除類別和已棄用的方法,以及引入新方法。
從 Spring Security 5 遷移到 Spring Security 6 可以增量完成,而不會破壞現有的程式碼庫。另外,我們可以使用OpenRewrite等第三方外掛程式來方便遷移到最新版本。
在本教程中,我們將學習如何使用 Spring Security 5 將現有應用程式移轉到 Spring Security 6。我們將取代已棄用的方法並利用 lambda DSL 來簡化配置。此外,我們將利用 OpenRewrite 來加快遷移速度。
2. Spring Security 和 Spring Boot 版本
Spring Boot基於Spring框架,Spring Boot的版本皆使用最新版本的Spring框架。 Spring Boot 2 預設使用 Spring Security 5,而 Spring Boot 3 使用 Spring Security 6。
要在 Spring Boot 應用程式中使用 Spring Security,我們始終將spring-boot-starter-security
相依性新增至pom.xml.
但是,我們可以透過在pom.xml
的properties
部分指定所需的版本來覆寫預設的 Spring Security 版本:
<properties>
<spring-security.version>5.8.9</spring-security.version>
</properties>
在這裡,我們指定在專案中使用 Spring Security 5.8.9,覆寫預設版本。
值得注意的是,我們也可以透過覆寫properties
部分中的預設版本來在 Spring Boot 2 中使用 Spring Security 6。
3. Spring Security 6 的新增功能
Spring Security 6 引入了多項功能更新以提高安全性和穩健性。它現在至少需要 Java 版本 17 並使用jakarta
命名空間。
主要變更之一是刪除了WebSecurityConfigurerAdapter
,轉而採用基於元件的安全配置。
此外, authorizeRequests()
被刪除並替換為authorizeHttpRequests()
來定義授權規則。
此外,它還引入了requestMatcher()
和securityMatcher()
等方法來取代antMatcher()
和 m vcMatcher()
來設定請求資源的安全性。 requestMatcher()
方法更安全,因為它為請求配置選擇適當的RequestMatcher
實作。
其他已棄用的方法(如cors()
和csrf()
現在有函數式風格的替代方法。
4. 項目設定
首先,讓我們透過將[spring-boot-starter-web](https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web)
和spring-boot-starter-security
加入pom.xml
來引導 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>
spring-boot-starter-security
相依性使用 Spring Security 5。
接下來,我們建立一個名為WebSecurityConfig
的類別:
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
}
在這裡,我們使用@EnableWebSecurity
註解該類別來啟動設定Web請求安全性的過程。此外,我們也啟用方法級授權。接下來,該類別擴充WebSecurityConfigurerAdapter
類別以提供各種安全設定方法。
此外,讓我們定義一個記憶體中使用者進行身份驗證:
@Override
void configure(AuthenticationManagerBuilder auth) throws Exception {
UserDetails user = User.withDefaultPasswordEncoder()
.username("Admin")
.password("password")
.roles("ADMIN")
.build();
auth.inMemoryAuthentication().withUser(user);
}
在上面的方法中,我們透過覆寫預設配置來建立記憶體中使用者。
繼續,讓我們透過重寫configure(WebSecurity web)
方法從安全性中排除靜態資源:
@Override
void configure(WebSecurity web) {
web.ignoring().antMatchers("/js/**", "/css/**");
}
最後,讓我們透過重寫configure(HttpSecurity http)
方法來建立HttpSecurity
:
@Override
void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic();
}
值得注意的是,此設定展示了典型的 Spring Security 5 配置。在後續部分中,我們將將此程式碼移轉到 Spring Security 6。
5. 將專案移轉到 Spring Security 6
Spring 建議採用增量遷移方法,以防止更新到 Spring Security 6 時破壞現有程式碼。在升級到Spring Security 6 之前,我們可以先將Spring Boot 應用程式升級到Spring Security 5.8.5 並更新程式碼以使用新功能。遷移到 5.8.5 讓我們為版本 6 中的預期變化做好準備。
在增量遷移時,我們的 IDE 可以警告我們已棄用的功能。這有助於增量更新過程。
為簡單起見,我們將應用程式更新為使用 Spring Boot 版本 3.2.2,將範例專案直接移轉到 Spring Security 6。如果應用程式使用 Spring Boot 版本 2,我們可以在properties
部分指定 Spring Security 6。
要開始遷移過程,讓我們修改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>
在初始設定中,我們使用 Spring Boot 2.7.5,它在底層使用 Spring Security 5。
值得注意的是,Spring Boot 3 的最低 Java 版本是 Java 17。
在後續小節中,我們將重構現有程式碼以使用 Spring Security 6。
5.1. @Configuration
註解
在 Spring Security 6 之前, @Configuration
註解是@EnableWebSecurity,
但是在最新的更新中,我們必須使用@Configuration
註解來註解我們的安全設定:
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
}
在這裡,我們將@Configuration
註解引入現有的程式碼庫中,因為它不再是@EnableWebSecurity
註解的一部分。此外,該註釋不再是@EnableMethodSecurity
、 @EnableWebFluxSecurity
或@EnableGlobalMethodSecurity
註釋的一部分。
此外, @EnableGlobalMethodSecurity
已標記為棄用並由@EnableMethodSecurity
替換。預設情況下,它啟用 Spring 的 pre-post 註解。因此,我們引入@EnableMethodSecurity
來提供方法層級的授權
5.2. WebSecurityConfigurerAdapter
最新更新刪除了WebSecurityConfigurerAdapter
類別並採用基於組件的配置:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
}
在這裡,我們刪除了WebSecurityConfigurerAdapter
,這消除了安全配置的重寫方法。相反,我們可以註冊一個 bean 來進行安全設定。我們可以註冊WebSecurityCustomizer
bean 來設定 Web 安全,註冊SecurityFilterChain
bean 來設定 HTTP 安全,註冊InMemoryUserDetails
bean 來註冊自訂使用者等。
5.3. WebSecurityCustomizer
Bean
讓我們透過發布WebSecurityCustomizer
bean 來修改排除靜態資源的方法:
@Bean
WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().requestMatchers("/js/**", "/css/**");
}
WebSecurityCustomizer
介面替換了WebSecurityConfigurerAdapter
介面中的configure(Websecurity web)
。
5.4. AuthenticationManager
Bean
在前面的部分中,我們透過從WebSecurityConfigurerAdapter
重寫configure(AuthenticationManagerBuilder auth)
創建了一個記憶體使用者。
讓我們透過註冊InMemoryUserDetailsManager
bean 來重構身份驗證憑證邏輯:
@Bean
InMemoryUserDetailsManager userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("Admin")
.password("admin")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
在這裡,我們定義一個具有 USER 角色的記憶體使用者來提供基於角色的授權。
5.5. HTTP 安全性配置
在先前的 Spring Security 版本中,我們透過重寫WebSecurityConfigurer
類別中的 configure 方法來設定HttpSecurity
。由於它在最新版本中被刪除,讓我們註冊SecurityFilterChain
bean 以進行 HTTP 安全配置:
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(
request -> request
.requestMatchers("/").permitAll()
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults())
.httpBasic(Customizer.withDefaults());
return http.build();
}
在上面的程式碼中,我們將authorizeRequest()
方法替換為authorizeHttpRequests()
。新方法使用AuthorizationManager
API,簡化了重複使用和自訂。
此外,它還透過延遲身份驗證查找來提高效能。僅當請求需要授權時才會進行身份驗證查找。
當我們沒有自訂規則時,我們使用Customizer.withDefaults()
方法來使用預設配置。
此外,我們使用requestMatchers()
而不是antMatcher()
或mvcMatcher()
來保護資源。
5.6. RequestCache
請求快取有助於在需要進行身份驗證時保存使用者請求,並在使用者成功進行身份驗證後將使用者重新導向到請求。在 Spring Security 6 之前, RequestCache
會檢查每個傳入請求,以查看是否有任何已儲存的請求要重新導向。這會讀取每個RequestCache
上的HttpSession
。
然而,在 Spring Security 6 中,請求快取僅檢查請求是否包含特殊參數名稱「 continue
」。這可以提高效能並防止不必要的HttpSession
讀取。
6.使用OpenRewrite
此外,我們可以使用 OpenRewrite 等第三方工具將現有的 Spring Boot 應用程式移轉到 Spring Boot 3。由於 Spring Boot 3 使用 Spring Security 6,因此它也將安全配置遷移到版本 6。
要使用 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>
這裡,我們透過recipe
屬性指定升級到Spring Boot版本3。 OpenRewrite 有很多用於升級 Java 專案的方法可供選擇。
最後,讓我們執行遷移命令:
$ mvn rewrite:run
上面的命令將專案遷移到 Spring Boot 3,包括安全性設定。但是,OpenRewrite 目前不使用 lambda DSL 進行遷移的安全配置。當然,這可能會在未來的版本中發生變化。
七、結論
在本文中,我們看到了透過替換已棄用的類別和方法將使用 Spring Security 5 的現有程式碼庫遷移到 Spring Security 6 的逐步指南。此外,我們也了解如何使用第三方外掛程式來自動遷移。與往常一樣,範例的完整原始程式碼可在 GitHub 上取得。