本章涵盖
- 实现和使用密码编码器
- 使用Spring Security Crypto模块提供的工具
在第 3 章中,我们讨论了在使用 Spring 安全性实现的应用程序中管理用户。但是密码呢?它们当然是身份验证流程中必不可少的部分。在本章中,您将学习如何在使用 Spring 安全性实现的应用程序中管理密码和机密。我们将讨论PasswordEncoder合约和Spring Security Crypto模块(SSCM)提供的用于管理密码的工具。
4.1 使用密码编码器
从第 3 章开始,您现在应该清楚地了解 UserDetails 接口是什么以及使用其实现的多种方式。但正如您在第 2 章中学到的,不同的参与者在身份验证和授权过程中管理用户表示。您还了解到其中一些具有默认值,例如UserDetailsService和PasswordEncoder。您现在知道可以覆盖默认值。我们继续深入了解这些 bean 以及实现它们的方法,因此在本节中,我们分析 密码编码器 .图 4.1 提醒您密码编码器在身份验证过程中的位置。
图 4.1 Spring 安全性身份验证过程。身份验证提供程序使用密码编码器在身份验证过程中验证用户的密码。
因为,一般来说,系统不会以纯文本形式管理密码,所以这些密码通常会经历一种转换,这使得阅读和窃取它们更具挑战性。对于此责任,Spring 安全性定义了一个单独的协定。为了在本节中轻松解释它,我提供了大量与 PasswordEncoder 实现相关的代码示例。我们将从理解合约开始,然后在项目中编写我们的实现。然后在 4.1.3 节中,我将为您提供 Spring Security 提供的最著名和最广泛使用的 PasswordEncoder 实现的列表。
4.1.1 密码编码器合约
在本节中,我们将讨论密码编码器合约的定义。您实现此协定以告知 Spring 安全性如何验证用户的密码。在身份验证过程中,密码编码器决定密码是否有效。每个系统都存储以某种方式编码的密码。您最好将它们散列存储,这样就没有人可以读取密码。密码编码器还可以对密码进行编码。合约声明的 encode() 和 matches() 方法实际上是其职责的定义。这两者都是同一合同的一部分,因为它们是紧密相连的,一个又一个。应用程序对密码进行编码的方式与验证密码的方式相关。让我们先来看看密码编码器接口的内容:
public interface PasswordEncoder {
String encode(CharSequence rawPassword);
boolean matches(CharSequence rawPassword, String encodedPassword);
default boolean upgradeEncoding(String encodedPassword) {
return false;
}
}
The interface defines two abstract methods and one with a default implementation. The abstract encode() and matches() methods are also the ones that you most often hear about when dealing with a PasswordEncoder implementation.
encode(CharSequence rawPassword)方法的目的是返回所提供字符串的转换。在 Spring 安全性功能方面,它用于为给定密码提供加密或哈希。之后可以使用matches(CharSequence rawPassword, String encodedPassword)方法来检查编码的字符串是否与原始密码匹配。在身份验证过程中使用 matches() 方法针对一组已知凭据测试提供的密码。第三种方法称为升级编码(CharSequence encodedPassword),在合约中默认为 false。如果覆盖它以返回 true,则会再次对编码的密码进行编码以提高安全性。
在某些情况下,对编码的密码进行编码可能会使从结果中获取明文密码更具挑战性。总的来说,这是我个人不喜欢的某种默默无闻。但是,如果您认为该框架适用于您的情况,则该框架为您提供了这种可能性。
4.1.2 实现密码编码器
正如你所观察到的,matches() 和 encode() 这两个方法有很强的关系。如果你覆盖它们,它们应该在功能方面始终对应:encode() 方法返回的字符串应该始终可以使用同一 PasswordEncoder 的 matches() 方法进行验证。在本部分中,你将实现 PasswordEncoder 协定并定义接口声明的两个抽象方法。了解如何实现密码编码器,您可以选择应用程序如何管理身份验证过程的密码。最直接的实现是密码编码器,它以纯文本形式考虑密码:也就是说,它不对密码进行任何编码。
以明文形式管理密码是NoOpPasswordEncoder实例精确执行的操作。我们在第 2 章的第一个示例中使用了这个类。如果您要编写自己的代码,它将类似于以下列表。
清单 4.1密码编码器的最简单实现
public class PlainTextPasswordEncoder
implements PasswordEncoder {
@Override
public String encode(CharSequence rawPassword) {
return rawPassword.toString(); #A
}
@Override
public boolean matches(
CharSequence rawPassword, String encodedPassword) {
return rawPassword.equals(encodedPassword); #B
}
}
编码的结果始终与密码相同。因此,要检查这些是否匹配,您只需要将字符串与 equals() 进行比较。使用哈希算法 SHA-512 的 PasswordEncoder 的简单实现看起来像下一个列表。
示例 4.2 实现使用 SHA-512 的密码编码器
public class Sha512PasswordEncoder
implements PasswordEncoder {
@Override
public String encode(CharSequence rawPassword) {
return hashWithSHA512(rawPassword.toString());
}
@Override
public boolean matches(
CharSequence rawPassword, String encodedPassword) {
String hashedPassword = encode(rawPassword);
return encodedPassword.equals(hashedPassword);
}
// Omitted code
}
在清单 4.2 中,我们使用一种方法对 SHA-512 提供的字符串值进行哈希处理。我在示例 4.2 中省略了此方法的实现,但您可以在示例 4.3 中找到它。我们从 encode() 方法调用此方法,该方法现在返回其输入的哈希值。为了根据输入验证哈希,matches() 方法对其输入中的原始密码进行哈希处理,并将其与执行验证的哈希进行比较。
示例 4.3 使用 SHA-512 对输入进行哈希处理的方法的实现
private String hashWithSHA512(String input) {
StringBuilder result = new StringBuilder();
try {
MessageDigest md = MessageDigest.getInstance("SHA-512");
byte [] digested = md.digest(input.getBytes());
for (int i = 0; i < digested.length; i++) {
result.append(Integer.toHexString(0xFF & digested[i]));
}
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Bad algorithm");
}
return result.toString();
}
您将在下一节中学习执行此操作的更好选项,因此现在不要过多地打扰此代码。
4.1.3 从提供的密码编码器实现中进行选择
虽然知道如何实现密码编码器功能强大,但您还必须意识到 Spring 安全性已经为您提供了一些有利的实现。如果其中一个与您的应用程序匹配,则无需重写它。在本节中,我们将讨论Spring Security提供的PasswordEncoder实现选项。这些是
- NoOpPasswordEncoder - 不对密码进行编码,但以明文形式保存密码。我们仅将此实现用于示例。因为它不散列密码, “慈善”你永远不应该在现实世界中使用它。
- 标准密码编码器 — 使用 SHA-256 对密码进行哈希处理。此实现现已弃用,并且“慈善”您不应该将其用于新实现。它被弃用的原因是它使用的哈希算法不再足够强大,但您可能仍然会在现有应用程序中发现此实现。最好,如果您在现有应用程序中找到它,则应使用其他更强大的密码编码器进行更改。
- Pbkdf2PasswordEncoder — 使用基于密码的密钥派生函数 2 (PBKDF2)。
- BCryptPasswordEncoder - 使用 bcrypt 强哈希函数对密码进行编码。
- SCryptPasswordEncoder — 使用 scrypt 哈希函数对密码进行编码。
有关哈希和这些算法的更多信息,您可以在“慈善”第 2 章中找到很好的讨论“David Wong 的真实世界密码学(Manning,2021 年)。这是链接:https://livebook.manning.com/book/real-world-cryptography/chapter-2/。
让我们看一些示例,说明如何创建这些类型的密码编码器实现的实例。 NoOpPasswordEncoder 不对密码进行编码。它的实现类似于清单 4.1 中示例中的 PlainTextPasswordEncoder。出于这个原因,我们只在理论示例中使用此密码编码器。此外,NoOpPasswordEncoder 类被设计为单例。你不能直接从类外部调用它的构造函数,但你可以使用 NoOpPasswordEncoder.getInstance() 方法来获取类的实例,如下所示:
PasswordEncoder p = NoOpPasswordEncoder.getInstance();
Spring Security 提供的 StandardPasswordEncoder 实现使用 SHA-256 对密码进行哈希处理。对于标准密码编码器,可以提供哈希过程中使用的机密。通过构造函数的参数设置此机密的值。如果选择调用无参数构造函数,则实现将使用空字符串作为键的值。但是,StandardPasswordEncoder 现已弃用,我不建议您在新实现中使用它。您可能会找到仍在使用它的旧应用程序或遗留代码,因此这就是您应该注意它的原因。下一个代码片段演示如何创建此密码编码器的实例:
PasswordEncoder p = new StandardPasswordEncoder();
PasswordEncoder p = new StandardPasswordEncoder("secret");
Spring Security 提供的另一个选项是 Pbkdf2PasswordEncoder 实现,它使用 PBKDF2 进行密码编码。若要创建 Pbkdf2PasswordEncoder 的实例,可以使用以下选项:
PasswordEncoder p =
New Pbkdf2PasswordEncoder(“secret”, 16, 310000,
[CA]Pbkdf2PasswordEncoder.
[CA]SecretKeyFactoryAlgorithm.PBKDF2WithHmacSHA256);
PBKDF2 是一个非常简单的慢速散列函数,它执行 HMAC 的次数与迭代参数指定的次数相同。最后一次调用收到的前三个参数是用于编码过程的密钥的值、用于编码密码的迭代次数以及哈希的大小。第二个和第三个参数会影响结果的强度。第四个参数给出哈希宽度。您可以从以下选项中进行选择:
- PBKDF2WithHmacSHA1
- PBKDF2WithHmacSHA256
- PBKDF2WithHmacSHA512
您可以选择更多或更少的迭代次数,以及结果的长度。哈希越长,密码越强大(哈希宽度相同)。但是,请注意,性能受以下值的影响:迭代次数越多,应用程序消耗的资源就越多。您应该在生成哈希所消耗的资源和所需的编码强度之间做出明智的折衷。
注意
在这本书中,我提到了你可能想了解更多的几个密码学概念。有关HMAC和其他密码学细节的相关信息,我推荐David Wong(Manning,2020)的真实世界密码学。该书的第3章提供了有关HMAC的详细信息。你可以在 https://livebook.manning.com/book/real-world-cryptography/chapter-3/ 找到这本书。
Spring Security提供的另一个很好的选择是BCryptPasswordEncoder,它使用bcrypt强哈希函数来编码密码。可以通过调用无参数构造函数来实例化 BCryptPasswordEncoder。但是,您也可以选择指定表示编码过程中使用的对数轮次(对数轮次)的强度系数。此外,您还可以更改用于编码的 SecureRandom 实例:
PasswordEncoder p = new BCryptPasswordEncoder();
PasswordEncoder p = new BCryptPasswordEncoder(4);
SecureRandom s = SecureRandom.getInstanceStrong();
PasswordEncoder p = new BCryptPasswordEncoder(4, s);
您提供的日志舍入值会影响哈希操作使用的迭代次数。使用的迭代次数为 2个对数轮。对于迭代次数计算,对数轮次的值只能介于 4 和 31 之间。可以通过调用第二个或第三个重载构造函数之一来指定此项,如前面的代码片段所示。
我介绍给你的最后一个选项是SCryptPasswordEncoder (图4.2)。此密码编码器使用 scrypt 哈希函数。对于 ScryptPasswordEncoder ,您可以使用以下选项来创建其实例,如图 4.2 所示。
图 4.2SCryptPasswordEncoder构造函数采用五个参数,并允许您配置 CPU 开销、内存开销、密钥长度和盐长度。
4.1.4 委托密码编码器的多种编码策略
在本节中,我们将讨论身份验证流必须应用各种实现来匹配密码的情况。您还将学习如何在应用程序中应用充当密码编码器的有用工具。此工具没有自己的实现,而是委托给实现密码编码器接口的其他对象。
在某些应用程序中,您可能会发现拥有各种密码编码器并根据某些特定配置从中进行选择很有用。我在生产应用程序中找到委派密码编码器的常见情况是,编码算法发生更改,从应用程序的特定版本开始。假设有人在当前使用的算法中发现了一个漏洞,并且您想为新注册的用户更改它,但您不想为现有凭据更改它。所以你最终会得到多种哈希。你如何处理这个案子?虽然这不是此方案的唯一方法,但一个不错的选择是使用 De委派密码编码器对象。
委派密码编码器是密码编码器接口的实现,该接口不是实现其编码算法,而是委托给同一协定的实现的另一个实例。哈希以命名用于定义该哈希的算法的前缀开头。委派密码编码器委托基于密码前缀的正确实现密码编码器。
这听起来很复杂,但通过一个例子,您可以观察到它非常简单。图 4.3 显示了密码编码器实例之间的关系。委派密码编码器具有它委派到的密码编码器实现的列表。 委派密码编码器将每个实例存储在映射中。 NoOpPasswordEncoder 被分配给 key noop,而 BCryptPasswordEncoder 实现被分配给 key bcrypt。当密码具有前缀 {noop} 时,DedelegateatingPasswordEncoder 会将操作委托给 NoOpPasswordEncoder 实现。如果前缀为 {bcrypt} ,则操作将委托给 BCryptPasswordEncoder 实现,如图 4.4 所示。
图 4.3 在本例中,DemissionatingPasswordEncoder为前缀 {noop} 注册了一个 NoOpPasswordEncoder,为前缀 {bcrypt} 注册了一个 BCryptPasswordEncoder,为前缀{scrypt}注册了一个SCryptPasswordEncoder。如果密码具有前缀{noop},则委派密码编码器会将操作转发到
图 4.4 在本例中,DemissionatingPasswordEncoder为前缀 {noop} 注册一个 NoOpPasswordEncoder,为前缀 {bcrypt} 注册一个 BCryptPasswordEncoder,为前缀{scrypt}注册一个SCryptPasswordEncoder。当密码具有前缀{bcrypt}时,DedelegateatingPasswordEncoder会将操作转发到BCryptPasswordEncoder实现。
接下来,让我们了解如何定义委派密码编码器。首先创建所需密码编码器实现的实例集合,然后将这些实例放在委派密码编码器中,如以下列表所示。
示例 4.4 创建委托密码编码器的实例
@Configuration
public class ProjectConfig {
// Omitted code
@Bean
public PasswordEncoder passwordEncoder() {
Map<String, PasswordEncoder> encoders = new HashMap<>();
encoders.put("noop", NoOpPasswordEncoder.getInstance());
encoders.put("bcrypt", new BCryptPasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
return new DelegatingPasswordEncoder("bcrypt", encoders);
}
}
DemissionatingPasswordEncoder只是一个充当PasswordEncoder的工具,因此当您必须从实现集合中进行选择时,可以使用它。在清单 4.4 中,声明的 DedelegateatingPasswordEncoder 实例包含对 NoOpPasswordEncoder、BCryptPasswordEncoder 和 SCryptPasswordEncoder 的引用,并将默认值委托给 BCryptPasswordEncoder 实现。 根据哈希的前缀,委派密码编码器使用正确的密码编码器实现来匹配密码。此前缀具有标识要从编码器映射中使用的密码编码器的键。如果没有前缀,委派密码编码器将使用默认编码器。默认的密码编码器是构造委派密码编码器实例时作为第一个参数给出的编码器。对于清单 4.4 中的代码,默认的 PasswordEncoder 是 bcrypt。
注意
大括号是哈希前缀的一部分,这些大括号应括在键的名称周围。例如,如果提供的哈希是 {noop }12345 ,则委派密码编码器委托给我们为前缀 noop 注册的 NoOpPasswordEncoder。同样,请记住,大括号在前缀中是必需的。
如果哈希看起来像下一个代码片段,则密码编码器是我们分配给前缀{bcrypt}的密码编码器,即BCryptPasswordEncoder。如果根本没有前缀,这也是应用程序将委派给的那个,因为我们将其定义为默认实现:
{bcrypt}$2a$10$xn3LI/AjqicFYZFruSwve.681477XaVNaUQbr1gioaWPn4t1KsnmG
为了方便起见,Spring 安全性提供了一种创建 DemissionatingPasswordEncoder 的方法,该编码器具有指向 PasswordEncoder 的所有标准实现的映射。PasswordEncoderFactories 类提供了一个 createDelegatingPasswordEncoder() 静态方法,该方法返回具有全套 PasswordEncoder 映射和 bcrypt 作为默认编码器的 DelegatingPasswordEncoder 的实现:
PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
编码、加密与哈希
在前面的部分中,我经常使用术语编码、加密和哈希。我想简要澄清这些术语以及我们在整本书中使用它们的方式。
编码是指给定输入的任何转换。例如,如果我们有一个反转字符串的函数 x,则应用于 ABCD 的函数 x -> y 会产生 DCBA .
加密是一种特殊类型的编码,要获取输出,您需要同时提供输入值和密钥。该键可以稍后选择谁应该能够反转功能(从输出中获取输入)。将加密表示为函数的最简单形式如下所示:
(x, k) -> y
其中 x 是输入, k 是密钥,y 是加密的结果。这样,知道密钥的个人可以使用已知函数从输出(y,k)->x获取输入。我们称此反向函数解密。如果用于加密的密钥与用于解密的密钥相同,我们通常称之为对称密钥。
如果我们有两个不同的密钥用于加密((x, k 1)->y)和解密((y,k 2)->x ),那么我们说加密是用非对称密钥完成的。 则( k 1,k 2)称为密钥对。用于加密的密钥 k 1 也称为公钥,而 k 2 称为私钥。 这样,只有私钥的所有者才能解密数据。
哈希是一种特殊类型的编码,只是函数只是一种方式。也就是说,从哈希函数的输出 y 中,您无法返回输入 x 。但是,应该总有一种方法可以检查输出 y 是否对应于输入 x ,因此我们可以将散列理解为一对用于编码和匹配的函数。如果散列是 x -> y,那么我们也应该有一个匹配函数 (x,y) ->布尔值。
有时,哈希函数也可以使用添加到输入中的随机值: (x, k) -> y 。我们将此值称为盐。盐使函数更强,强制应用反向函数从结果中获取输入的难度。
为了总结本书中迄今为止我们讨论和应用的合同,表4.1简要描述了每个组成部分。
表 4.1 表示 Spring 安全性中身份验证流的主协定的接口
合同 | 描述 |
用户详细信息 | 表示 Spring 安全性看到的用户。 |
授予权限 | 定义应用程序用途内允许用户的操作(例如,读取、写入、删除等)。 |
用户详细信息服务 | 表示用于按用户名检索用户详细信息的对象。 |
用户详细信息管理器 | 一个更特殊的合同 用户详细信息服务.除了按用户名检索用户外,它还可用于更改用户集合或特定用户。 |
密码编码器 | 指定如何加密或哈希密码,以及如何检查给定的编码字符串是否与纯文本密码匹配。 |
4.2 利用 Spring 安全加密模块
在本节中,我们将讨论 Spring Security Crypto 模块 (SSCM),它是 Spring Security 中处理密码学的部分。使用 Java 语言不提供开箱即用的加密和解密函数以及生成密钥。这限制了开发人员添加依赖项,为这些功能提供更易于访问的方法。
为了使我们的生活更轻松,Spring 安全性还提供了自己的解决方案,它使您能够通过消除使用单独库的需要来减少项目的依赖性。密码编码器也是 SSCM 的一部分,即使我们在前面的部分中分别处理了它们。在本节中,我们将讨论SSCM提供哪些与加密相关的其他选项。您将看到如何使用 SSCM 中的两个基本功能的示例:
- “慈善”密钥生成器 - 用于生成用于哈希和加密算法的密钥的对象
- “charitalics”加密器 - 用于加密和解密数据的对象
4.2.1 使用密钥生成器
在本节中,我们将讨论密钥生成器。“慈善”密钥生成器是用于生成特定类型的密钥的对象,通常用于加密或哈希算法。Spring 安全性提供的密钥生成器的实现是很棒的实用工具。您更愿意使用这些实现,而不是为应用程序添加另一个依赖项,这就是我建议您了解它们的原因。让我们看一些有关如何创建和应用密钥生成器的代码示例。
两个接口表示两种主要类型的密钥生成器: BytesKeyGenerator 和 StringKeyGenerator。我们可以通过使用工厂类直接构建它们 钥匙生成器 .可以使用字符串密钥生成器(由 StringKeyGenerator 合约表示)以字符串形式获取密钥。通常,我们将此密钥用作哈希或加密算法的盐值。您可以在以下代码片段中找到 StringKeyGenerator 合约的定义:
public interface StringKeyGenerator {
String generateKey();
}
生成器只有一个 generateKey() 方法,该方法返回表示键值的字符串。下一个代码片段提供了如何获取 StringKeyGenerator 实例以及如何使用它来获取盐值的示例:
StringKeyGenerator keyGenerator = KeyGenerators.string();
String salt = keyGenerator.generateKey();
生成器创建一个 8 字节密钥,并将其编码为十六进制字符串。该方法以字符串形式返回这些操作的结果。描述密钥生成器的第二个接口是 字节密钥生成器 ,其定义如下:
public interface BytesKeyGenerator {
int getKeyLength();
byte[] generateKey();
}
除了以 byte[] 形式返回键的 generateKey() 方法之外,该接口还定义了另一个以字节数返回键长度的方法。默认的字节密钥生成器生成 8 字节长度的密钥:
BytesKeyGenerator keyGenerator = KeyGenerators.secureRandom();
byte [] key = keyGenerator.generateKey();
int keyLength = keyGenerator.getKeyLength();
在前面的代码片段中,密钥生成器生成 8 字节长度的密钥。如果要指定不同的密钥长度,可以在获取密钥生成器实例时通过向 KeyGenerators.secureRandom() 方法提供所需的值来执行此操作:
BytesKeyGenerator keyGenerator = KeyGenerators.secureRandom(16);
使用 KeyGenerators.secureRandom() 方法创建的 BytesKeyGenerator 生成的密钥对于 generateKey() 方法的每次调用都是唯一的。在某些情况下,我们更喜欢为同一密钥生成器的每次调用返回相同键值的实现。在这种情况下,我们可以用KeyGenerators.shared(int length)方法创建一个BytesKeyGenerator。在此代码段中, key1 和 key2 具有相同的值:
BytesKeyGenerator keyGenerator = KeyGenerators.shared(16);
byte [] key1 = keyGenerator.generateKey();
byte [] key2 = keyGenerator.generateKey();
4.2.2 使用加密器加密和解密机密
在本节中,我们将应用Spring Security提供的加密器实现以及代码示例。“慈善”加密器是实现加密算法的对象。在谈论安全性时,加密和解密是常见的操作,因此预计在您的应用程序中需要这些操作。
在系统组件之间发送数据或持久化数据时,我们经常需要加密数据。加密器提供的操作是加密和解密。SSCM定义了两种类型的加密器: 字节加密器和 文本加密器。虽然它们具有类似的职责,但它们处理不同的数据类型。 TextEncryptor 将数据作为字符串进行管理。它的方法接收字符串作为输入,返回字符串作为输出,从其接口的定义中可以看出:
public interface TextEncryptor {
String encrypt(String text);
String decrypt(String encryptedText);
}
BytesEncryptor更通用。您以字节数组的形式提供其输入数据:
public interface BytesEncryptor {
byte[] encrypt(byte[] byteArray);
byte[] decrypt(byte[] encryptedByteArray);
}
让我们找出构建和使用加密器所需的选项。工厂类加密器为我们提供了多种可能性。对于 BytesEncryptor,我们可以使用 Encryptors.standard() 或 Encryptors.stronger() 方法,如下所示:
String salt = KeyGenerators.string().generateKey();
String password = "secret";
String valueToEncrypt = "HELLO";
BytesEncryptor e = Encryptors.standard(password, salt);
byte [] encrypted = e.encrypt(valueToEncrypt.getBytes());
byte [] decrypted = e.decrypt(encrypted);
在后台,标准字节加密器使用 256 字节 AES 加密来加密输入。要构建字节加密器的更强实例,可以调用 Encryptors.stronger() 方法:
BytesEncryptor e = Encryptors.stronger(password, salt);
差异很小,发生在幕后,其中 256 位上的 AES 加密使用伽罗瓦/计数器模式 (GCM) 作为操作模式。标准模式使用密码块链接 (CBC),这被认为是一种较弱的方法。
文本加密器有三种主要类型。您可以通过调用 Encryptors.text() 、Encryptors.delux() 或 Encryptors.queryableText() 方法来创建这三种类型。 除了这些创建加密器的方法之外,还有一个返回虚拟文本加密器的方法,它不加密值。您可以将虚拟文本加密器用于演示示例或案例,在这些示例中,您希望测试应用程序的性能,而无需花费时间进行加密。返回此无操作加密器的方法是 Encryptors.noOpText() 。在下面的代码片段中,您将找到使用文本加密器的示例。即使它是对加密器的调用,在示例中, 加密和 valueToEncrypt 是相同的:
String valueToEncrypt = "HELLO";
TextEncryptor e = Encryptors.noOpText();
String encrypted = e.encrypt(valueToEncrypt);
Encryptors.text() encryptor 使用 Encryptors.standard() 方法来管理加密操作,而 Encryptors.delux() 方法使用 Encryptors.stronger() 实例,如下所示:
String salt = KeyGenerators.string().generateKey();
String password = "secret";
String valueToEncrypt = "HELLO";
TextEncryptor e = Encryptors.text(password, salt); #A
String encrypted = e.encrypt(valueToEncrypt);
String decrypted = e.decrypt(encrypted);
4.3 小结
- 密码编码器在身份验证逻辑中具有最关键的职责之一 - 处理密码。
- Spring Security 在散列算法方面提供了几种替代方案,这使得实现只是一个选择问题。
- Spring 安全加密模块 (SSCM) 为密钥生成器和加密器的实现提供了各种替代方案。
- 密钥生成器是实用工具对象,可帮助您生成与加密算法一起使用的密钥。
- 加密器是实用程序对象,可帮助您应用数据的加密和解密。
本文暂时没有评论,来添加一个吧(●'◡'●)