This commit is contained in:
parent
fc79b80e69
commit
0c99c66172
|
|
@ -21,7 +21,6 @@ public class EsDataEncryptUtil {
|
||||||
private static final Set<String> DATE_FIELD_PREFIXES = new HashSet<>(Arrays.asList(
|
private static final Set<String> DATE_FIELD_PREFIXES = new HashSet<>(Arrays.asList(
|
||||||
"createTime", "updateTime", "lastTime", "startTime", "endTime", "birthDate", "nextContactTime"
|
"createTime", "updateTime", "lastTime", "startTime", "endTime", "birthDate", "nextContactTime"
|
||||||
));
|
));
|
||||||
|
|
||||||
private static EncryptionService getEncryptionService() {
|
private static EncryptionService getEncryptionService() {
|
||||||
if (encryptionService == null) {
|
if (encryptionService == null) {
|
||||||
encryptionService = ApplicationContextHolder.getBean(EncryptionService.class);
|
encryptionService = ApplicationContextHolder.getBean(EncryptionService.class);
|
||||||
|
|
@ -63,7 +62,7 @@ public class EsDataEncryptUtil {
|
||||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||||
String key = entry.getKey();
|
String key = entry.getKey();
|
||||||
Object value = entry.getValue();
|
Object value = entry.getValue();
|
||||||
decryptedMap.put(key, decryptValue(value));
|
decryptedMap.put(key, decryptValue(key,value));
|
||||||
}
|
}
|
||||||
return decryptedMap;
|
return decryptedMap;
|
||||||
}
|
}
|
||||||
|
|
@ -133,7 +132,7 @@ public class EsDataEncryptUtil {
|
||||||
* 根据值类型进行解密
|
* 根据值类型进行解密
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private static Object decryptValue(Object value) {
|
private static Object decryptValue(String key,Object value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -142,7 +141,8 @@ public class EsDataEncryptUtil {
|
||||||
String strValue = (String) value;
|
String strValue = (String) value;
|
||||||
// 对已加密的数据进行解密
|
// 对已加密的数据进行解密
|
||||||
if (strValue.startsWith(Const.ENCRYPTED_PREFIX)) {
|
if (strValue.startsWith(Const.ENCRYPTED_PREFIX)) {
|
||||||
return getEncryptionService().decryptAes(strValue.substring(Const.ENCRYPTED_PREFIX.length()));
|
String newValue = getEncryptionService().decryptAes(strValue.substring(Const.ENCRYPTED_PREFIX.length()));
|
||||||
|
return desensitization(key,newValue);
|
||||||
}
|
}
|
||||||
return strValue;
|
return strValue;
|
||||||
} else if (value instanceof Map) {
|
} else if (value instanceof Map) {
|
||||||
|
|
@ -152,14 +152,27 @@ public class EsDataEncryptUtil {
|
||||||
// 递归处理List中的每个元素
|
// 递归处理List中的每个元素
|
||||||
List<Object> decryptedList = new ArrayList<>();
|
List<Object> decryptedList = new ArrayList<>();
|
||||||
for (Object item : (List<Object>) value) {
|
for (Object item : (List<Object>) value) {
|
||||||
decryptedList.add(decryptValue(item));
|
decryptedList.add(decryptValue(key,item));
|
||||||
}
|
}
|
||||||
return decryptedList;
|
return decryptedList;
|
||||||
}
|
}
|
||||||
// 其他类型保持不变
|
// 其他类型保持不变
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 数据脱敏
|
||||||
|
private static String desensitization(String key,String value){
|
||||||
|
if ("mobile".equals(key)) {
|
||||||
|
return SensitiveDataMaskUtil.maskPhone(value);
|
||||||
|
}else if ("email".equals(key)) {
|
||||||
|
return SensitiveDataMaskUtil.maskEmail(value);
|
||||||
|
}else if ("ownerDeptName".equals(key)) {
|
||||||
|
return SensitiveDataMaskUtil.maskName(value);
|
||||||
|
}else if ("address".equals(key)) {
|
||||||
|
return SensitiveDataMaskUtil.maskAddress(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 判断字段是否为日期类型字段
|
* 判断字段是否为日期类型字段
|
||||||
* @param fieldName 字段名
|
* @param fieldName 字段名
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,150 @@
|
||||||
|
package com.kakarote.core.security.util;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 敏感数据脱敏工具类
|
||||||
|
* 提供姓名、手机号、地址等敏感信息的脱敏处理
|
||||||
|
*/
|
||||||
|
public class SensitiveDataMaskUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对姓名进行脱敏处理
|
||||||
|
* 规则:
|
||||||
|
* 1. 单字名:显示姓氏,其余用*代替
|
||||||
|
* 2. 双字名:显示姓氏,名用*代替
|
||||||
|
* 3. 多字名:显示姓氏和最后一个字,中间用*代替
|
||||||
|
* 4. 长度不足的情况:直接返回原字符串
|
||||||
|
*
|
||||||
|
* @param name 姓名
|
||||||
|
* @return 脱敏后的姓名
|
||||||
|
*/
|
||||||
|
public static String maskName(String name) {
|
||||||
|
if (StringUtils.isBlank(name)) {
|
||||||
|
return StringUtils.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
int length = name.length();
|
||||||
|
if (length == 1) {
|
||||||
|
// 单字名,直接返回
|
||||||
|
return name;
|
||||||
|
} else if (length == 2) {
|
||||||
|
// 双字名,显示姓氏
|
||||||
|
return name.charAt(0) + "*";
|
||||||
|
} else if (length == 3) {
|
||||||
|
// 三字名,显示姓氏和最后一个字
|
||||||
|
return name.charAt(0) + "*" + name.charAt(2);
|
||||||
|
} else {
|
||||||
|
// 多字名,显示姓氏和最后一个字,中间用*代替
|
||||||
|
return name.charAt(0) + StringUtils.repeat("*", length - 2) + name.charAt(length - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对手机号码进行脱敏处理
|
||||||
|
* 规则:保留前3位和后4位,中间用*代替
|
||||||
|
*
|
||||||
|
* @param phone 手机号码
|
||||||
|
* @return 脱敏后的手机号码
|
||||||
|
*/
|
||||||
|
public static String maskPhone(String phone) {
|
||||||
|
if (StringUtils.isBlank(phone) || phone.length() < 11) {
|
||||||
|
return phone;
|
||||||
|
}
|
||||||
|
return phone.substring(0, 3) + "****" + phone.substring(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对地址进行脱敏处理
|
||||||
|
* 规则:
|
||||||
|
* 1. 保留省、市、区,后面的详细地址用*代替
|
||||||
|
* 2. 如果地址较短,保留前8个字符,后面用*代替
|
||||||
|
*
|
||||||
|
* @param address 地址
|
||||||
|
* @return 脱敏后的地址
|
||||||
|
*/
|
||||||
|
public static String maskAddress(String address) {
|
||||||
|
if (StringUtils.isBlank(address)) {
|
||||||
|
return StringUtils.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
int length = address.length();
|
||||||
|
if (length <= 8) {
|
||||||
|
// 地址较短,保留前半部分
|
||||||
|
int keepLength = Math.max(1, length / 2);
|
||||||
|
return address.substring(0, keepLength) + StringUtils.repeat("*", length - keepLength);
|
||||||
|
} else {
|
||||||
|
// 地址较长,保留前8个字符
|
||||||
|
return address.substring(0, 8) + "****";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对邮箱进行脱敏处理
|
||||||
|
* 规则:保留前2位和域名,中间用*代替
|
||||||
|
*
|
||||||
|
* @param email 邮箱地址
|
||||||
|
* @return 脱敏后的邮箱
|
||||||
|
*/
|
||||||
|
public static String maskEmail(String email) {
|
||||||
|
if (StringUtils.isBlank(email) || !email.contains("@")) {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] parts = email.split("@");
|
||||||
|
if (parts.length != 2) {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
String username = parts[0];
|
||||||
|
String domain = parts[1];
|
||||||
|
|
||||||
|
if (username.length() <= 2) {
|
||||||
|
// 用户名较短,全部用*代替
|
||||||
|
return StringUtils.repeat("*", username.length()) + "@" + domain;
|
||||||
|
} else {
|
||||||
|
// 保留前2位,其余用*代替
|
||||||
|
return username.substring(0, 2) + StringUtils.repeat("*", username.length() - 2) + "@" + domain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对身份证号进行脱敏处理
|
||||||
|
* 规则:保留前6位和后4位,中间用*代替
|
||||||
|
*
|
||||||
|
* @param idCard 身份证号
|
||||||
|
* @return 脱敏后的身份证号
|
||||||
|
*/
|
||||||
|
public static String maskIdCard(String idCard) {
|
||||||
|
if (StringUtils.isBlank(idCard) || idCard.length() < 18) {
|
||||||
|
return idCard;
|
||||||
|
}
|
||||||
|
return idCard.substring(0, 6) + StringUtils.repeat("*", 8) + idCard.substring(14);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用脱敏方法
|
||||||
|
*
|
||||||
|
* @param str 原始字符串
|
||||||
|
* @param start 保留的开始位置(包含)
|
||||||
|
* @param end 保留的结束位置(包含)
|
||||||
|
* @return 脱敏后的字符串
|
||||||
|
*/
|
||||||
|
public static String maskGeneral(String str, int start, int end) {
|
||||||
|
if (StringUtils.isBlank(str)) {
|
||||||
|
return StringUtils.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
int length = str.length();
|
||||||
|
if (start < 0 || end < 0 || start >= length || end >= length || start >= end) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(str.substring(0, start));
|
||||||
|
sb.append(StringUtils.repeat("*", end - start + 1));
|
||||||
|
sb.append(str.substring(end + 1));
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,6 +12,7 @@ import com.kakarote.core.common.SystemCodeEnum;
|
||||||
import com.kakarote.core.exception.CrmException;
|
import com.kakarote.core.exception.CrmException;
|
||||||
import com.kakarote.core.feign.admin.entity.SimpleUser;
|
import com.kakarote.core.feign.admin.entity.SimpleUser;
|
||||||
import com.kakarote.core.field.FieldService;
|
import com.kakarote.core.field.FieldService;
|
||||||
|
import com.kakarote.core.security.util.EsDataEncryptUtil;
|
||||||
import com.kakarote.core.servlet.ApplicationContextHolder;
|
import com.kakarote.core.servlet.ApplicationContextHolder;
|
||||||
import com.kakarote.core.utils.UserCacheUtil;
|
import com.kakarote.core.utils.UserCacheUtil;
|
||||||
import com.kakarote.crm.constant.CrmEnum;
|
import com.kakarote.crm.constant.CrmEnum;
|
||||||
|
|
@ -458,10 +459,12 @@ public class InitEsIndexRunner implements ApplicationRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// 在创建IndexRequest之前加密数据
|
||||||
|
Map<String, Object> encryptedMap = EsDataEncryptUtil.encryptMap(map);
|
||||||
|
|
||||||
IndexRequest request = new IndexRequest(crmEnum.getIndex(), "_doc");
|
IndexRequest request = new IndexRequest(crmEnum.getIndex(), "_doc");
|
||||||
request.id(map.get(crmEnum.getPrimaryKey()).toString());
|
request.id(encryptedMap.get(crmEnum.getPrimaryKey()).toString());
|
||||||
request.source(map);
|
request.source(encryptedMap);
|
||||||
bulkRequest.add(request);
|
bulkRequest.add(request);
|
||||||
if (bulkRequest.requests().size() >= 1000) {
|
if (bulkRequest.requests().size() >= 1000) {
|
||||||
bulk(bulkRequest);
|
bulk(bulkRequest);
|
||||||
|
|
@ -510,7 +513,10 @@ public class InitEsIndexRunner implements ApplicationRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
request.doc(map);
|
// 在创建UpdateRequest之前加密数据
|
||||||
|
Map<String, Object> encryptedMap = EsDataEncryptUtil.encryptMap(map);
|
||||||
|
|
||||||
|
request.doc(encryptedMap);
|
||||||
bulkRequest.add(request);
|
bulkRequest.add(request);
|
||||||
if (bulkRequest.requests().size() >= 1000) {
|
if (bulkRequest.requests().size() >= 1000) {
|
||||||
bulk(bulkRequest);
|
bulk(bulkRequest);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue