From b16a08eb1a4f633afa8c9ad43d7f7a6ebb502a08 Mon Sep 17 00:00:00 2001 From: wkc <978997012@qq.com> Date: Mon, 30 Mar 2026 10:51:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=B4=B7=E6=AC=BE=E5=AE=9A?= =?UTF-8?q?=E4=BB=B7=E6=95=8F=E6=84=9F=E5=AD=97=E6=AE=B5=E5=8A=A0=E8=A7=A3?= =?UTF-8?q?=E5=AF=86=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application.yml | 4 ++ .../LoanPricingSensitiveDisplayService.java | 46 +++++++++++++ .../service/SensitiveFieldCryptoService.java | 68 +++++++++++++++++++ ...oanPricingSensitiveDisplayServiceTest.java | 24 +++++++ .../SensitiveFieldCryptoServiceTest.java | 32 +++++++++ 5 files changed, 174 insertions(+) create mode 100644 ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/LoanPricingSensitiveDisplayService.java create mode 100644 ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/SensitiveFieldCryptoService.java create mode 100644 ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/LoanPricingSensitiveDisplayServiceTest.java create mode 100644 ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/SensitiveFieldCryptoServiceTest.java diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 7a09b6d..7ec4567 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -103,3 +103,7 @@ xss: security: password-transfer: key: "1234567890abcdef" + +loan-pricing: + sensitive: + key: "1234567890abcdef" diff --git a/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/LoanPricingSensitiveDisplayService.java b/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/LoanPricingSensitiveDisplayService.java new file mode 100644 index 0000000..d2c315f --- /dev/null +++ b/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/LoanPricingSensitiveDisplayService.java @@ -0,0 +1,46 @@ +package com.ruoyi.loanpricing.service; + +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +@Service +public class LoanPricingSensitiveDisplayService +{ + public String maskCustName(String custName) + { + if (!StringUtils.hasText(custName)) + { + return custName; + } + if (custName.contains("公司") && custName.length() > 4) + { + return custName.substring(0, 2) + "*".repeat(custName.length() - 4) + custName.substring(custName.length() - 2); + } + if (custName.length() == 1) + { + return custName; + } + return custName.substring(0, 1) + "*".repeat(custName.length() - 1); + } + + public String maskIdNum(String idNum) + { + if (!StringUtils.hasText(idNum)) + { + return idNum; + } + if (idNum.startsWith("91") && idNum.length() == 18) + { + return idNum.substring(0, 2) + "*".repeat(13) + idNum.substring(idNum.length() - 3); + } + if (idNum.matches("\\d{17}[\\dXx]")) + { + return idNum.substring(0, 4) + "*".repeat(8) + idNum.substring(idNum.length() - 4); + } + if (idNum.length() > 5) + { + return idNum.substring(0, 2) + "*".repeat(idNum.length() - 5) + idNum.substring(idNum.length() - 3); + } + return "*".repeat(idNum.length()); + } +} diff --git a/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/SensitiveFieldCryptoService.java b/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/SensitiveFieldCryptoService.java new file mode 100644 index 0000000..6e051e3 --- /dev/null +++ b/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/SensitiveFieldCryptoService.java @@ -0,0 +1,68 @@ +package com.ruoyi.loanpricing.service; + +import com.ruoyi.common.exception.ServiceException; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +@Service +public class SensitiveFieldCryptoService +{ + private final String key; + + public SensitiveFieldCryptoService(@Value("${loan-pricing.sensitive.key:}") String key) + { + this.key = key; + } + + public String encrypt(String plainText) + { + validateKey(); + if (!StringUtils.hasText(plainText)) + { + return plainText; + } + try + { + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES")); + return Base64.getEncoder().encodeToString(cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8))); + } + catch (Exception ex) + { + throw new ServiceException("贷款定价敏感字段加密失败"); + } + } + + public String decrypt(String cipherText) + { + validateKey(); + if (!StringUtils.hasText(cipherText)) + { + return cipherText; + } + try + { + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES")); + return new String(cipher.doFinal(Base64.getDecoder().decode(cipherText)), StandardCharsets.UTF_8); + } + catch (Exception ex) + { + throw new ServiceException("贷款定价敏感字段解密失败"); + } + } + + private void validateKey() + { + if (!StringUtils.hasText(key)) + { + throw new IllegalStateException("loan-pricing.sensitive.key 未配置"); + } + } +} diff --git a/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/LoanPricingSensitiveDisplayServiceTest.java b/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/LoanPricingSensitiveDisplayServiceTest.java new file mode 100644 index 0000000..2071487 --- /dev/null +++ b/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/LoanPricingSensitiveDisplayServiceTest.java @@ -0,0 +1,24 @@ +package com.ruoyi.loanpricing.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +class LoanPricingSensitiveDisplayServiceTest +{ + private final LoanPricingSensitiveDisplayService displayService = new LoanPricingSensitiveDisplayService(); + + @Test + void shouldMaskPersonalNameAndIdNum() + { + assertEquals("张*", displayService.maskCustName("张三")); + assertEquals("1101********1234", displayService.maskIdNum("110101199001011234")); + } + + @Test + void shouldMaskCorporateNameAndCreditCode() + { + assertEquals("测试****公司", displayService.maskCustName("测试科技有限公司")); + assertEquals("91*************00X", displayService.maskIdNum("91110000100000000X")); + } +} diff --git a/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/SensitiveFieldCryptoServiceTest.java b/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/SensitiveFieldCryptoServiceTest.java new file mode 100644 index 0000000..6b7f551 --- /dev/null +++ b/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/SensitiveFieldCryptoServiceTest.java @@ -0,0 +1,32 @@ +package com.ruoyi.loanpricing.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class SensitiveFieldCryptoServiceTest +{ + @Test + void shouldEncryptAndDecryptCustNameAndIdNum() + { + SensitiveFieldCryptoService service = new SensitiveFieldCryptoService("1234567890abcdef"); + + String nameCipher = service.encrypt("张三"); + String idNumCipher = service.encrypt("110101199001011234"); + + assertNotEquals("张三", nameCipher); + assertNotEquals("110101199001011234", idNumCipher); + assertEquals("张三", service.decrypt(nameCipher)); + assertEquals("110101199001011234", service.decrypt(idNumCipher)); + } + + @Test + void shouldRejectBlankKeyConfiguration() + { + SensitiveFieldCryptoService service = new SensitiveFieldCryptoService(""); + + assertThrows(IllegalStateException.class, () -> service.encrypt("张三")); + } +}