cn.hutool
hutool-crypto
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/CustomEncryptorConfig.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/CustomEncryptorConfig.java
new file mode 100644
index 00000000..2d091de8
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/CustomEncryptorConfig.java
@@ -0,0 +1,44 @@
+package org.dromara.common.encrypt.config;
+
+import org.jasypt.encryption.StringEncryptor;
+import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
+import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.context.annotation.Bean;
+
+/**
+ * Jasypt 自定义加密器配置
+ *
+ * @author zdxt
+ */
+@AutoConfiguration
+public class CustomEncryptorConfig {
+
+ /**
+ * 加密密钥
+ */
+ private static final String CRACK = "ATPfOhpnAVp6yBas7RU";
+
+ @Bean("jasyptStringEncryptor")
+ public StringEncryptor jasyptStringEncryptor() {
+ return createEncryptor();
+ }
+
+ /**
+ * 创建加密器实例(Bean 注册和 main 方法共用)
+ */
+ private static PooledPBEStringEncryptor createEncryptor() {
+ PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
+ SimpleStringPBEConfig config = new SimpleStringPBEConfig();
+ config.setPassword(CRACK);
+ config.setAlgorithm("PBEWithMD5AndDES");
+ config.setKeyObtentionIterations("1000");
+ config.setPoolSize("1");
+ config.setProviderName("SunJCE");
+ config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
+ config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
+ config.setStringOutputType("base64");
+ encryptor.setConfig(config);
+ return encryptor;
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
index 132cf295..6d7da8c5 100644
--- a/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -1,3 +1,4 @@
org.dromara.common.encrypt.config.EncryptorAutoConfiguration
org.dromara.common.encrypt.config.ApiDecryptAutoConfiguration
+org.dromara.common.encrypt.config.CustomEncryptorConfig
diff --git a/zdxt-web-server/zdxt-admin-web-server/src/main/resources/application-dev.yml b/zdxt-web-server/zdxt-admin-web-server/src/main/resources/application-dev.yml
index c0d8d1c1..9bbce0e2 100644
--- a/zdxt-web-server/zdxt-admin-web-server/src/main/resources/application-dev.yml
+++ b/zdxt-web-server/zdxt-admin-web-server/src/main/resources/application-dev.yml
@@ -58,9 +58,9 @@ spring:
driverClassName: com.mysql.cj.jdbc.Driver
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
- url: jdbc:mysql://localhost:3309/zfjd-refactoring-v3?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
- username: root
- password: root
+ url: ENC(/EKCnamZackeZIip+AZjSAd7HHa1C4Pzh+rEEXWIZbvjWPOyeE+KlbsBDwrU88lXth0/1No6X+xhJahoO7hEpsmZeTpKg/+3r3lzDpUj9zL1rTgjggHLa5T2m3N7mNF0X2gyxe5FlrMOsY7qJ08BdmQ9QZInx5IUZXnRSy0dX7dk18mSNp3VLvTFwsNowW2okMlWtlWCL6tRMb3MvFcmh8CXgiD4oaW2PJ7sYdttAbSl0X71omw2d/XfEmOonPb23waYKuBILlU0lLAkpM9BuqUILcUeiVCZUS9/asP9nZh6+BNT8qkpZkU/4rSsJQUrWsSO5kilXRqTA/PVnTkHlCghxgp2Jgk4DHi8+Mu2sUN7vyW+ZcUiew==)
+ username: ENC(fe0dFsZDxnT+2WCXoRah3kJLfzX0pc81)
+ password: ENC(fe0dFsZDxnT+2WCXoRah3kJLfzX0pc81)
# # 从库数据源
# slave:
# lazy: true
diff --git a/zdxt-web-server/zdxt-admin-web-server/src/test/java/com/zdxt/service/test/JasyptEncryptDecryptTest.java b/zdxt-web-server/zdxt-admin-web-server/src/test/java/com/zdxt/service/test/JasyptEncryptDecryptTest.java
new file mode 100644
index 00000000..97bffc1d
--- /dev/null
+++ b/zdxt-web-server/zdxt-admin-web-server/src/test/java/com/zdxt/service/test/JasyptEncryptDecryptTest.java
@@ -0,0 +1,112 @@
+package com.zdxt.service.test;
+
+import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
+import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
+import org.junit.jupiter.api.*;
+
+/**
+ * Jasypt 加解密测试
+ *
+ * 与 CustomEncryptorConfig 使用相同的密钥和算法配置,
+ * 可直接运行获取加密后的密文用于配置文件 ENC(...) 占位。
+ *
+ *
+ * @author zdxt
+ */
+@DisplayName("Jasypt 加解密测试")
+public class JasyptEncryptDecryptTest {
+
+ private static final String CRACK = "ATPfOhpnAVp6yBas7RU";
+
+ private static PooledPBEStringEncryptor encryptor;
+
+ @BeforeAll
+ public static void init() {
+ encryptor = new PooledPBEStringEncryptor();
+ SimpleStringPBEConfig config = new SimpleStringPBEConfig();
+ config.setPassword(CRACK);
+ config.setAlgorithm("PBEWithMD5AndDES");
+ config.setKeyObtentionIterations("1000");
+ config.setPoolSize("1");
+ config.setProviderName("SunJCE");
+ config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
+ config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
+ config.setStringOutputType("base64");
+ encryptor.setConfig(config);
+ }
+
+ @DisplayName("加密原文并输出密文")
+ @Test
+ public void testEncrypt() {
+ // ===== 修改此处为需要加密的原文 =====
+ String plainText = "jdbc:mysql://localhost:3309/zfjd-refactoring-v3?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true";
+ plainText="root";
+
+ String encrypted = encryptor.encrypt(plainText);
+ Assertions.assertNotNull(encrypted, "密文不应为 null");
+ Assertions.assertFalse(encrypted.isBlank(), "密文不应为空");
+
+ System.out.println("========== 加密结果 ==========");
+ System.out.println("原文: " + plainText);
+ System.out.println("密文: " + encrypted);
+ System.out.println("配置文件使用: ENC(" + encrypted + ")");
+ }
+
+ @DisplayName("加密后解密应还原为原文")
+ @Test
+ public void testEncryptAndDecrypt() {
+ String plainText = "test_encrypt_decrypt_123";
+
+ String encrypted = encryptor.encrypt(plainText);
+ String decrypted = encryptor.decrypt(encrypted);
+
+ Assertions.assertEquals(plainText, decrypted, "解密结果应与原文一致");
+ System.out.println("加密解密验证通过: " + plainText + " -> " + encrypted + " -> " + decrypted);
+ }
+
+ @DisplayName("同一原文多次加密应产生不同密文(随机盐)")
+ @Test
+ public void testRandomSaltProducesDifferentCiphertext() {
+ String plainText = "same_plain_text";
+
+ String encrypted1 = encryptor.encrypt(plainText);
+ String encrypted2 = encryptor.encrypt(plainText);
+
+ Assertions.assertNotEquals(encrypted1, encrypted2, "随机盐下同一原文两次加密结果应不同");
+ // 但两次密文都能正确解密
+ Assertions.assertEquals(plainText, encryptor.decrypt(encrypted1));
+ Assertions.assertEquals(plainText, encryptor.decrypt(encrypted2));
+ System.out.println("随机盐验证通过:");
+ System.out.println(" 密文1: " + encrypted1);
+ System.out.println(" 密文2: " + encrypted2);
+ }
+
+ @DisplayName("解密错误密文应抛出异常")
+ @Test
+ public void testDecryptInvalidCiphertext() {
+ Assertions.assertThrows(Exception.class, () -> encryptor.decrypt("invalid_ciphertext"),
+ "解密非法密文应抛出异常");
+ System.out.println("非法密文解密异常验证通过");
+ }
+
+ @DisplayName("批量加密 - 在此添加需要加密的原文")
+ @Test
+ public void testBatchEncrypt() {
+ // ===== 在此添加需要加密的原文列表 =====
+ String[] plainTexts = {
+ "your_db_password",
+ "your_redis_password"
+ };
+
+ System.out.println("========== 批量加密结果 ==========");
+ for (String text : plainTexts) {
+ String encrypted = encryptor.encrypt(text);
+ System.out.println("原文: " + text);
+ System.out.println("配置: ENC(" + encrypted + ")");
+ System.out.println("-----------------------------------");
+
+ // 验证可解密
+ Assertions.assertEquals(text, encryptor.decrypt(encrypted));
+ }
+ }
+}