小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
写在前面
上文我们聊到Security中的加密技术,今天我们来实践下,怎么自定义Security中的加密。同说多说一句,欢迎大家点击头像去查看Security专栏,我们一起学习下。
自定义 PasswordEncoder
上文已经说过PasswordEncoder的加密技术。但是尽管Spring Security 已经为我们提供了丰富的 PasswordEncoder,但你也可以通过实现这个接口来设计满足自身需求的任意一种密码编解码和验证机制。
例如,我们可以编写如下所示的一个 PlainTextPasswordEncoder:
public class PlainTextPasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence rawPassword) {
return rawPassword.toString();
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return rawPassword.equals(encodedPassword);
}
}
PlainTextPasswordEncoder 的功能与 NoOpPasswordEncoder 类似,没有对明文进行任何处理。如果你想使用某种算法集成 PasswordEncoder,就可以实现类似如下所示的 Sha512PasswordEncoder,这里使用了 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);
}
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();
}
}
-
上述代码中,hashWithSHA512() 方法就使用了前面提到的单向散列加密算法来生成消息摘要(Message Digest),其主要特点在于单向不可逆和密文长度固定。
-
SHA(Secure Hash Algorithm)以及MD5(Message Digest 5)都是常见的单向散列加密算法,在 JDK 自带的 MessageDigest 类中已经包含了默认实现,我们直接调用方法即可。
Spring Security 加密模块
正如上一篇文章所讲,使用 Spring Security 时,通常涉及用户认证的部分会用到加解密技术。但就应用场景而言,加解密技术是一种通用的基础设施类技术,不仅可以用于用户认证,也可以用于其他任何涉及敏感数据处理的场景。
因此,Spring Security 也充分考虑到了这种需求,专门提供了一个加密模式(Spring Security Crypto Module,SSCM)。
请注意,尽管 PasswordEncoder 也属于这个模块的一部分,但这个模块本身是高度独立的,我们可以脱离于用户认证流程来使用这个模块。
Spring Security 加密模块的核心功能有两部分:
- 首先就是加解密器(Encryptors),典型的使用方式如下:
BytesEncryptor e = Encryptors.standard(password, salt);
上述方法使用了标准的 256 位 AES 算法对输入的 password 字段进行加密,返回的是一个 BytesEncryptor。同时,我们也看到这里需要输入一个代表盐值的 salt 字段。
- 而这个 salt 值的获取就可以用到 Spring Security 加密模块的另一个功能——键生成器(Key Generators),使用方式如下所示:
String salt = KeyGenerators.string().generateKey();
上述键生成器会创建一个 8 字节的密钥,并将其编码为十六进制字符串。
如果将加解密器和键生成器结合起来,我们就可以实现通用的加解密机制,如下所示:
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);
在日常开发过程中,你可以根据需要调整上述代码并嵌入到我们的系统中。
OK 今天我们自定义的加密就到这里
总结
对于一个 Web 应用程序而言,一旦需要实现用户认证,势必涉及用户密码等敏感信息的加密。为此,Spring Security 专门提供了 PasswordEncoder 组件对密码进行加解密。Spring Security 内置了一批即插即用的 PasswordEncoder,并通过代理机制完成了各个组件的版本兼容和统一管理。这种设计思想也值得我们学习和借鉴
弦外之音
感谢你的阅读,如果你感觉学到了东西,麻烦您点赞,关注。也欢迎有问题我们下面评论交流
加油! 我们下期再见!
给大家分享几个我前面写的几篇骚操作