微服务SpringBoot整合Jasypt加密工具
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
文章目录
一、Jasypt介绍
Jasypt是Java加密工具包能支持对密码的哈希加密对文本和二进制数据的对称加解密还能集成SpringBoot项目对配置文件中的密钥进行加密存储。
引入依赖如下
<!-- https://mvnrepository.com/artifact/com.github.ulisesbocchio/jasypt-spring-boot-starter -->
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.4</version>
</dependency>
二、Jasypt手动使用
2.1 密码加密场景
用户注册账户的时候需要输入密码我们将密码加密后保存到数据库中保证用户的敏感数据的安全性。当用户再次登录的时候我们需要将登录密码和注册时保存的密文密码进行比对只有比对一致才能完成登录。
密码加密工具类主要有三个它们都是实现了PasswordEncryptor
接口下面我们逐步来看。
@Slf4j
@RestController
public class SignController {
private final BasicPasswordEncryptor basicPasswordEncryptor = new BasicPasswordEncryptor();
private String encryptedPassword = null;
@GetMapping("/signup/{password}")
public String signup(@PathVariable String password){
log.info("用户注册密码为{}", password);
encryptedPassword = basicPasswordEncryptor.encryptPassword(password);
log.info("用户注册密码加密后为{}", encryptedPassword);
return encryptedPassword;
}
@GetMapping("/signin/{password}")
public String signin(@PathVariable String password){
log.info("用户登录密码为{}", password);
if(basicPasswordEncryptor.checkPassword(password, encryptedPassword)){
log.info("用户登录成功");
return "success";
}
log.info("用户登录失败");
return "fail";
}
}
启动项目后我们首先注册用户密码localhost:8080/signup/123456
就能得到密文5b32ygn5pbBvphjIKco6X8Z2VfWqwEUw
并将其保存到类变量中暂存当我们再次登录localhost:8080/signin/123456
就能登录成功了。相反的如果登录时密码随意输错就会登录失败。
2022-10-11 15:41:57.038 INFO 26268 --- [nio-8080-exec-1] c.e.myapp.controller.SignController : 用户注册密码为123456
2022-10-11 15:41:57.039 INFO 26268 --- [nio-8080-exec-1] c.e.myapp.controller.SignController : 用户注册密码加密后为5b32ygn5pbBvphjIKco6X8Z2VfWqwEUw
2022-10-11 15:42:07.405 INFO 26268 --- [nio-8080-exec-3] c.e.myapp.controller.SignController : 用户登录密码为123456
2022-10-11 15:42:07.406 INFO 26268 --- [nio-8080-exec-3] c.e.myapp.controller.SignController : 用户登录成功
2022-10-11 15:42:12.767 INFO 26268 --- [nio-8080-exec-4] c.e.myapp.controller.SignController : 用户登录密码为123457
2022-10-11 15:42:12.767 INFO 26268 --- [nio-8080-exec-4] c.e.myapp.controller.SignController : 用户登录失败
那么这种加密方式是什么呢我们可以打开BasicPasswordEncryptor
的源码看到类上面的注释
- Algorithm: MD5.
- Salt size: 8 bytes.
- Iterations: 1000.
意思就是使用的MD5这种哈希算法并且使用8字节64位的盐值迭代计算1000次得到的密文。
除了使用如上的BasicPasswordEncryptor
工具之外还有StrongPasswordEncryptor
工具类它的加密登记更加的安全
- Algorithm: SHA-256.
- Salt size: 16 bytes.
- Iterations: 100000.
如果这些加密算法都不能满足你的要求就可以使用ConfigurablePasswordEncryptor
来自定义加密工具类ConfigurablePasswordEncryptor
可以设置自己需要使用的算法。
总结
接口类PasswordEncryptor
主要有如下三个实现类
BasicPasswordEncryptor
使用MD5算法StrongPasswordEncryptor
使用SHA-256算法ConfigurablePasswordEncryptor
可自定义指定哈希算法
哈希算法是不可逆的因此只有加密encryptPassword和检查checkPassword两个方法。
2.2 文本加密场景
用户的手机号、身份证号等敏感信息在存储的时候需要进行加密但是这些敏感数据在需要使用的时候是需要明文解密的因此不适合使用2.1节的哈希算法而是使用对称加密的形式。
文本加密工具类主要有三个它们都是实现了TextEncryptor
接口下面我们逐步来看。
@Slf4j
@RestController
public class TextController {
private static final BasicTextEncryptor basicTextEncryptor = new BasicTextEncryptor();
private static final String SECRET = "hello";
private String encryptedText = null;
static {
basicTextEncryptor.setPassword(SECRET);
}
@GetMapping("/encryptText/{plainText}")
public String encryptText(@PathVariable String plainText){
log.info("用户输入明文{}", plainText);
encryptedText = basicTextEncryptor.encrypt(plainText);
log.info("用户加密密文{}", encryptedText);
return encryptedText;
}
@GetMapping("/decryptText")
public String decryptText(){
String plainText = basicTextEncryptor.decrypt(encryptedText);
log.info("用户原始明文{}", plainText);
return plainText;
}
}
项目启动后我们分别访问localhost:8080/encryptText/hello
进行加密访问localhost:8080/decryptText
进行解密。
2022-10-11 15:52:36.949 INFO 21652 --- [nio-8080-exec-1] c.e.myapp.controller.TextController : 用户输入明文hello
2022-10-11 15:52:36.950 INFO 21652 --- [nio-8080-exec-1] c.e.myapp.controller.TextController : 用户加密密文u/qYluhyFpyOA6xMD3z3JA==
2022-10-11 15:52:46.345 INFO 21652 --- [nio-8080-exec-2] c.e.myapp.controller.TextController : 用户原始明文hello
我们同样打开BasicTextEncryptor
可以看到它的加密原理
- Algorithm: PBEWithMD5AndDES.
- Key obtention iterations: 1000.
同样的我们可以使用安全性更高的StrongTextEncryptor
- Algorithm: PBEWithMD5AndTripleDES.
- Key obtention iterations: 1000.
还有安全性更高的AES256TextEncryptor
- Algorithm: PBEWithHMACSHA512AndAES_256".
- Key obtention iterations: 1000.
2.3 数值加密场景
如果需要对整数或者小数进行加密就可以分别使用IntegerNumberEncryptor
接口和DecimalNumberEncryptor
接口的实现类。同样的这种场景的加密也都是对称加密用法完全一样。
IntegerNumberEncryptor主要用来对整数进行加解密。
- BasicIntegerNumberEncryptor
- Algorithm: PBEWithMD5AndDES.
- Key obtention iterations: 1000.
- StrongIntegerNumberEncryptor
- Algorithm: PBEWithMD5AndTripleDES.
- Key obtention iterations: 1000.
- AES256IntegerNumberEncryptor
- Algorithm: PBEWithHMACSHA512AndAES_256.
- Key obtention iterations: 1000.
DecimalNumberEncryptor主要用来对小数进行加解密。
- BasicDecimalNumberEncryptor
- Algorithm: PBEWithMD5AndDES.
- Key obtention iterations: 1000.
- StrongDecimalNumberEncryptor
- Algorithm: PBEWithMD5AndTripleDES.
- Key obtention iterations: 1000.
- AES256DecimalNumberEncryptor
- Algorithm: PBEWithHMACSHA512AndAES_256.
- Key obtention iterations: 1000.
2.4 二进制数据加密场景
暂未遇到需要加密二进制数据的业务场景此处略过使用方法可以参考官网。
三、Jasypt整合SpringBoot
SpringBoot应用中有很多密钥和密码都是存储在配置文件中的我们需要将它们以密文的方式存储起来。
# 服务器配置
server:
port: 8080
# Spring配置
spring:
# 数据源配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&&serverTimezone=Asia/Shanghai&&useSSL=false
username: root
# 此处是密码的密文要用ENC()进行包裹
password: ENC(KZeGx0ixuy4UrBp1HuhiDNnKB0cJr0cW)
# mybatis配置
mybatis:
mapper-locations: classpath:mapper/*Mapper.xml
# 加密配置
jasypt:
encryptor:
# 指定加密密钥生产环境请放到启动参数里面
password: your-secret
# 指定解密算法需要和加密时使用的算法一致
algorithm: PBEWithMD5AndDES
# 指定initialization vector类型
iv-generator-classname: org.jasypt.iv.NoIvGenerator
如上是对数据库密码进行加密存储密文是怎么的来的可以写一个测试类使用第二节介绍的内容自己手动加密。
@Slf4j
public final class JasyptUtils {
/**
* 加密使用密钥
*/
private static final String PRIVATE_KEY = "lybgeek";
private static BasicTextEncryptor basicTextEncryptor = new BasicTextEncryptor();
static {
basicTextEncryptor.setPassword(PRIVATE_KEY);
}
/**
* 私有构造方法防止被意外实例化
*/
private JasyptUtils() {
}
/**
* 明文加密
*
* @param plaintext 明文
* @return String
*/
public static String encrypt(String plaintext) {
log.info("明文字符串为{}", plaintext);
// 使用的加密算法参考2.2节内容也可以在源码的类注释中看到
String ciphertext = basicTextEncryptor.encrypt(plaintext);
log.info("密文字符串为{}", ciphertext);
return ciphertext;
}
/**
* 解密
*
* @param ciphertext 密文
* @return String
*/
public static String decrypt(String ciphertext) {
log.info("密文字符串为{}", ciphertext);
ciphertext = "ENC(" + ciphertext + ")";
if (PropertyValueEncryptionUtils.isEncryptedValue(ciphertext)) {
String plaintext = PropertyValueEncryptionUtils.decrypt(ciphertext, basicTextEncryptor);
log.info("明文字符串为{}", plaintext);
return plaintext;
}
log.error("解密失败");
return "";
}
}
@Slf4j
public class JasyptUtilsTest {
@Test
public void testEncrypt(){
String plainText = "Glrs@1234";
String ciperText = JasyptUtils.encrypt(plainText);
log.info("加密后的密文为{}", ciperText);
}
@Test
public void testDecrypt(){
String ciperText = "KZeGx0ixuy4UrBp1HuhiDNnKB0cJr0cW";
String plainText = JasyptUtils.decrypt(ciperText);
log.info("解密后的明文为{}", plainText);
}
}
经过如上的配置启动项目如下从数据库获取数据的应用逻辑就能正常使用了。
@Slf4j
@RestController
public class HelloController {
@Autowired
UserMapper userMapper;
@GetMapping("/getHello")
public String getHello(){
log.info("myapp works!");
List<User> users = userMapper.listUsers();
return users.toString();
}
}
@Mapper
public interface UserMapper {
List<User> listUsers();
}
<mapper namespace="com.example.myapp.mapper.UserMapper">
<select id="listUsers" resultType="com.example.myapp.bean.User">
select zu.user_id userId, zu.user_name userName, zu.age age, zu.user_email userEmail from zx_user zu;
</select>
</mapper>
四、生成环境启动
生产环境密钥作为启动参数
java -jar -Djasypt.encryptor.password=your-secret
无、参考文档
Jasypt: Java simplified encryption - Jasypt: Java simplified encryption - Main