新增贷款定价敏感字段加解密服务
This commit is contained in:
@@ -103,3 +103,7 @@ xss:
|
||||
security:
|
||||
password-transfer:
|
||||
key: "1234567890abcdef"
|
||||
|
||||
loan-pricing:
|
||||
sensitive:
|
||||
key: "1234567890abcdef"
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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 未配置");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
@@ -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("张三"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user