From 39be636d4ebb8fae94ea7fff15b87d4e7320f933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BA=84=E9=94=90=E6=B3=A2?= <10549902+zhuangruibo@user.noreply.gitee.com> Date: Thu, 23 Apr 2026 22:50:56 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 17 +++ ruoyi-common/ruoyi-common-encrypt/pom.xml | 12 ++ .../encrypt/config/CustomEncryptorConfig.java | 44 +++++++ ...ot.autoconfigure.AutoConfiguration.imports | 1 + .../src/main/resources/application-dev.yml | 6 +- .../test/JasyptEncryptDecryptTest.java | 112 ++++++++++++++++++ 6 files changed, 189 insertions(+), 3 deletions(-) create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/CustomEncryptorConfig.java create mode 100644 zdxt-web-server/zdxt-admin-web-server/src/test/java/com/zdxt/service/test/JasyptEncryptDecryptTest.java diff --git a/pom.xml b/pom.xml index aff5e195..315a0b42 100644 --- a/pom.xml +++ b/pom.xml @@ -48,6 +48,9 @@ 8.7.3-20251210 1.8.4 + + 1.9.3 + 4.0.3 2025.0.0 @@ -298,6 +301,20 @@ ${bouncycastle.version} + + + org.jasypt + jasypt + ${jasypt.version} + + + + + com.github.ulisesbocchio + jasypt-spring-boot-starter + ${jasypt-spring-boot.version} + + io.github.linpeilie mapstruct-plus-spring-boot-starter diff --git a/ruoyi-common/ruoyi-common-encrypt/pom.xml b/ruoyi-common/ruoyi-common-encrypt/pom.xml index 02b9062d..de26ce98 100644 --- a/ruoyi-common/ruoyi-common-encrypt/pom.xml +++ b/ruoyi-common/ruoyi-common-encrypt/pom.xml @@ -27,6 +27,18 @@ bcpkix-jdk18on + + + org.jasypt + jasypt + + + + + com.github.ulisesbocchio + jasypt-spring-boot-starter + + 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)); + } + } +}