对于最新的稳定版本,请使用 Spring Security 6.4.1! |
为 6.0 做准备
Spring Security 团队已经准备了 5.8 版本,以简化到 Spring Security 6.0 的升级。 使用 5.8 和以下步骤在更新到 6.0 时最大限度地减少更改。
更新到 Spring Security 5.8
第一步是确保您是 Spring Boot 2.7 的最新补丁版本。 接下来,您应该确保您使用的是 Spring Security 5.8 的最新补丁版本。 如果您使用的是 Spring Boot,则需要将 Spring Boot 版本从 Spring Security 5.7 覆盖到 5.8。 Spring Security 5.8 与 Spring Security 5.7 完全兼容,因此与 Spring Boot 2.7 完全兼容。 有关如何更新到 Spring Security 5.8 的说明,请访问参考指南的获取 Spring Security 部分。
更新密码编码
在 6.0 中,更新了 PBKDF2、SCrypt 和 Argon2 的密码编码最小值。
如果您使用的是默认密码编码器,则无需遵循任何准备步骤,可以跳过此部分。 |
更新Pbkdf2PasswordEncoder
如果您使用的是 Pbkdf2PasswordEncoder
,则构造函数将替换为引用给定设置适用的 Spring Security 版本的静态工厂。
替换已弃用的构造函数用法
如果使用默认构造函数,则应首先更改:
-
Java
-
Kotlin
@Bean
PasswordEncoder passwordEncoder() {
return new Pbkdf2PasswordEncoder();
}
@Bean
fun passwordEncoder(): PasswordEncoder {
return Pbkdf2PasswordEncoder()
}
自:
-
Java
-
Kotlin
@Bean
PasswordEncoder passwordEncoder() {
return Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_5();
}
@Bean
fun passwordEncoder(): PasswordEncoder {
return Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_5()
}
或者,如果您有自定义设置,请更改为指定所有设置的构造函数,如下所示:
-
Java
-
Kotlin
@Bean
PasswordEncoder passwordEncoder() {
PasswordEncoder current = new Pbkdf2PasswordEncoder("mysecret".getBytes(UTF_8), 320000);
return current;
}
@Bean
fun passwordEncoder(): PasswordEncoder {
val current: PasswordEncoder = Pbkdf2PasswordEncoder("mysecret".getBytes(UTF_8), 320000)
return current
}
更改它们以使用完全指定的构造函数,如下所示:
-
Java
-
Kotlin
@Bean
PasswordEncoder passwordEncoder() {
PasswordEncoder current = new Pbkdf2PasswordEncoder("mysecret".getBytes(UTF_8), 16, 185000, 256);
return current;
}
@Bean
fun passwordEncoder(): PasswordEncoder {
val current: PasswordEncoder = Pbkdf2PasswordEncoder("mysecret".getBytes(UTF_8), 16, 185000, 256)
return current
}
用DelegatingPasswordEncoder
未使用已弃用的构造函数后,下一步是使用 .
以下代码将委托编码器配置为检测正在使用的密码并将其替换为最新的密码:DelegatingPasswordEncoder
current
-
Java
-
Kotlin
@Bean
PasswordEncoder passwordEncoder() {
String prefix = "[email protected]";
PasswordEncoder current = // ... see previous step
PasswordEncoder upgraded = Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8();
DelegatingPasswordEncoder delegating = new DelegatingPasswordEncoder(prefix, Map.of(prefix, upgraded));
delegating.setDefaultPasswordEncoderForMatches(current);
return delegating;
}
@Bean
fun passwordEncoder(): PasswordEncoder {
String prefix = "[email protected]"
PasswordEncoder current = // ... see previous step
PasswordEncoder upgraded = Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8()
DelegatingPasswordEncoder delegating = new DelegatingPasswordEncoder(prefix, Map.of(prefix, upgraded))
delegating.setDefaultPasswordEncoderForMatches(current)
return delegating
}
更新SCryptPasswordEncoder
如果你使用的是SCryptPasswordEncoder
,则构造函数将替换为静态工厂,这些工厂引用给定设置适用的 Spring Security 版本。
替换已弃用的构造函数用法
如果使用默认构造函数,则应首先更改:
-
Java
-
Kotlin
@Bean
PasswordEncoder passwordEncoder() {
return new SCryptPasswordEncoder();
}
@Bean
fun passwordEncoder(): PasswordEncoder {
return SCryptPasswordEncoder()
}
自:
-
Java
-
Kotlin
@Bean
PasswordEncoder passwordEncoder() {
return SCryptPasswordEncoder.defaultsForSpringSecurity_v4_1();
}
@Bean
fun passwordEncoder(): PasswordEncoder {
return SCryptPasswordEncoder.defaultsForSpringSecurity_v4_1()
}
用DelegatingPasswordEncoder
未使用已弃用的构造函数后,下一步是使用 .
以下代码将委托编码器配置为检测正在使用的密码并将其替换为最新的密码:DelegatingPasswordEncoder
current
-
Java
-
Kotlin
@Bean
PasswordEncoder passwordEncoder() {
String prefix = "[email protected]";
PasswordEncoder current = // ... see previous step
PasswordEncoder upgraded = SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8();
DelegatingPasswordEncoder delegating = new DelegatingPasswordEncoder(prefix, Map.of(prefix, upgraded));
delegating.setDefaultPasswordEncoderForMatches(current);
return delegating;
}
@Bean
fun passwordEncoder(): PasswordEncoder {
String prefix = "[email protected]"
PasswordEncoder current = // ... see previous step
PasswordEncoder upgraded = SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8()
DelegatingPasswordEncoder delegating = new DelegatingPasswordEncoder(prefix, Map.of(prefix, upgraded))
delegating.setDefaultPasswordEncoderForMatches(current)
return delegating
}
更新Argon2PasswordEncoder
如果你使用的是Argon2PasswordEncoder
,则构造函数将替换为静态工厂,这些工厂引用给定设置适用的 Spring Security 版本。
替换已弃用的构造函数用法
如果使用默认构造函数,则应首先更改:
-
Java
-
Kotlin
@Bean
PasswordEncoder passwordEncoder() {
return new Argon2PasswordEncoder();
}
@Bean
fun passwordEncoder(): PasswordEncoder {
return Argon2PasswordEncoder()
}
自:
-
Java
-
Kotlin
@Bean
PasswordEncoder passwordEncoder() {
return Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2();
}
@Bean
fun passwordEncoder(): PasswordEncoder {
return Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2()
}
用DelegatingPasswordEncoder
未使用已弃用的构造函数后,下一步是使用 .
以下代码将委托编码器配置为检测正在使用的密码并将其替换为最新的密码:DelegatingPasswordEncoder
current
-
Java
-
Kotlin
@Bean
PasswordEncoder passwordEncoder() {
String prefix = "[email protected]";
PasswordEncoder current = // ... see previous step
PasswordEncoder upgraded = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8();
DelegatingPasswordEncoder delegating = new DelegatingPasswordEncoder(prefix, Map.of(prefix, upgraded));
delegating.setDefaultPasswordEncoderForMatches(current);
return delegating;
}
@Bean
fun passwordEncoder(): PasswordEncoder {
String prefix = "[email protected]"
PasswordEncoder current = // ... see previous step
PasswordEncoder upgraded = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8()
DelegatingPasswordEncoder delegating = new DelegatingPasswordEncoder(prefix, Map.of(prefix, upgraded))
delegating.setDefaultPasswordEncoderForMatches(current)
return delegating
}
停止使用Encryptors.queryableText
Encryptors.queryableText(CharSequence,CharSequence)
是不安全的,因为相同的 input 数据将产生相同的 output。
它已被弃用,并将在 6.0 中删除;Spring Security 不再支持以这种方式加密数据。
要升级,您需要使用支持的机制重新加密或将其解密存储。
考虑以下伪代码,用于从 table 中读取每个加密的条目,对其进行解密,然后使用支持的机制对其进行重新加密:
-
Java
TextEncryptor deprecated = Encryptors.queryableText(password, salt);
BytesEncryptor aes = new AesBytesEncryptor(password, salt, KeyGenerators.secureRandom(12), CipherAlgorithm.GCM);
TextEncryptor supported = new HexEncodingTextEncryptor(aes);
for (MyEntry entry : entries) {
String value = deprecated.decrypt(entry.getEncryptedValue()); (1)
entry.setEncryptedValue(supported.encrypt(value)); (2)
entryService.save(entry)
}
1 | - 以上使用 deprecated 将值转换为纯文本。queryableText |
2 | - 然后,使用支持的 Spring Security 机制重新加密该值。 |
有关 Spring Security 支持哪些加密机制的更多信息,请参阅参考手册。