对于最新的稳定版本,请使用 Spring Security 6.3.1Spring中文文档

对于最新的稳定版本,请使用 Spring Security 6.3.1Spring中文文档

Spring Security 团队准备了 5.8 版本,以简化到 Spring Security 6.0 的升级。 使用 5.8 和以下步骤在更新到 6.0 时最大程度地减少更改。Spring中文文档

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 的说明,请访问参考指南的 Getting Spring Security 部分。Spring中文文档

更新密码编码

在 6.0 中,更新了 PBKDF2、SCrypt 和 Argon2 的密码编码最低要求。Spring中文文档

如果您使用的是默认密码编码器,则无需执行任何准备步骤,可以跳过此部分。Spring中文文档

更新Pbkdf2PasswordEncoder

如果使用的是 Pbkdf2PasswordEncoder,则构造函数将替换为引用给定设置适用的 Spring Security 版本的静态工厂。Spring中文文档

替换已弃用的构造函数用法

如果使用默认构造函数,则应首先更改:Spring中文文档

@Bean
PasswordEncoder passwordEncoder() {
    return new Pbkdf2PasswordEncoder();
}
@Bean
fun passwordEncoder(): PasswordEncoder {
    return Pbkdf2PasswordEncoder()
}
@Bean
PasswordEncoder passwordEncoder() {
    return Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_5();
}
@Bean
fun passwordEncoder(): PasswordEncoder {
    return Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_5()
}

或者,如果您有自定义设置,请更改为指定所有设置的构造函数,如下所示:Spring中文文档

@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
}

更改它们以使用完全指定的构造函数,如下所示:Spring中文文档

@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

一旦未使用已弃用的构造函数,下一步就是准备代码,以便使用 升级到最新标准。 以下代码将委派编码器配置为检测正在使用的密码,并将其替换为最新版本:DelegatingPasswordEncodercurrentSpring中文文档

@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 版本的静态工厂。Spring中文文档

替换已弃用的构造函数用法

如果使用默认构造函数,则应首先更改:Spring中文文档

@Bean
PasswordEncoder passwordEncoder() {
    return new SCryptPasswordEncoder();
}
@Bean
fun passwordEncoder(): PasswordEncoder {
    return SCryptPasswordEncoder()
}
@Bean
PasswordEncoder passwordEncoder() {
    return SCryptPasswordEncoder.defaultsForSpringSecurity_v4_1();
}
@Bean
fun passwordEncoder(): PasswordEncoder {
    return SCryptPasswordEncoder.defaultsForSpringSecurity_v4_1()
}

DelegatingPasswordEncoder

一旦未使用已弃用的构造函数,下一步就是准备代码,以便使用 升级到最新标准。 以下代码将委派编码器配置为检测正在使用的密码,并将其替换为最新版本:DelegatingPasswordEncodercurrentSpring中文文档

@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 版本的静态工厂。Spring中文文档

替换已弃用的构造函数用法

如果使用默认构造函数,则应首先更改:Spring中文文档

@Bean
PasswordEncoder passwordEncoder() {
	return new Argon2PasswordEncoder();
}
@Bean
fun passwordEncoder(): PasswordEncoder {
	return Argon2PasswordEncoder()
}
@Bean
PasswordEncoder passwordEncoder() {
	return Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2();
}
@Bean
fun passwordEncoder(): PasswordEncoder {
	return Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2()
}

DelegatingPasswordEncoder

一旦未使用已弃用的构造函数,下一步就是准备代码,以便使用 升级到最新标准。 以下代码将委派编码器配置为检测正在使用的密码,并将其替换为最新版本:DelegatingPasswordEncodercurrentSpring中文文档

@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
}

如果您使用的是默认密码编码器,则无需执行任何准备步骤,可以跳过此部分。Spring中文文档

停止使用Encryptors.queryableText

Encryptors.queryableText(CharSequence,CharSequence)是不安全的,因为相同的输入数据将产生相同的输出。 它已被弃用,并将在 6.0 中删除;Spring Security 不再支持以这种方式加密数据。Spring中文文档

要升级,您需要使用受支持的机制重新加密或将其解密存储。Spring中文文档

请考虑以下伪代码,用于从表中读取每个加密条目,对其进行解密,然后使用受支持的机制重新加密它:Spring中文文档

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支持的加密机制的更多信息,请参阅参考手册。Spring中文文档

1 - 上面使用 deprecated 将值转换为明文。queryableText
2 - 然后,使用支持的 Spring Security 机制重新加密该值。

执行特定于应用程序的步骤

接下来,您需要根据它是 Servlet 还是 Reactive 应用程序来执行一些步骤。Spring中文文档