This commit is contained in:
zhangwenzan 2025-08-28 15:26:06 +08:00
parent 4d5ebd13e8
commit fc79b80e69
3 changed files with 202 additions and 5 deletions

View File

@ -0,0 +1,177 @@
package com.kakarote.core.security.util;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.kakarote.core.common.Const;
import com.kakarote.core.common.FieldEnum;
import com.kakarote.core.security.EncryptionService;
import com.kakarote.core.servlet.ApplicationContextHolder;
import org.springframework.util.CollectionUtils;
import java.util.*;
/**
* Elasticsearch数据加密解密工具类
*/
public class EsDataEncryptUtil {
private static EncryptionService encryptionService;
// 日期类型字段的前缀列表可根据实际情况扩展
private static final Set<String> DATE_FIELD_PREFIXES = new HashSet<>(Arrays.asList(
"createTime", "updateTime", "lastTime", "startTime", "endTime", "birthDate", "nextContactTime"
));
private static EncryptionService getEncryptionService() {
if (encryptionService == null) {
encryptionService = ApplicationContextHolder.getBean(EncryptionService.class);
}
return encryptionService;
}
/**
* 加密Map中的所有String类型字段但跳过日期类型字段
*/
public static Map<String, Object> encryptMap(Map<String, Object> map) {
if (map == null || map.isEmpty()) {
return map;
}
Map<String, Object> encryptedMap = new HashMap<>(map.size());
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
// 检查是否为日期类型字段如果是则不加密
if (isDateField(key) && value instanceof String) {
encryptedMap.put(key, value);
} else {
encryptedMap.put(key, encryptValue(value));
}
}
return encryptedMap;
}
/**
* 解密Map中的所有字段
*/
public static Map<String, Object> decryptMap(Map<String, Object> map) {
if (map == null || map.isEmpty()) {
return map;
}
Map<String, Object> decryptedMap = new HashMap<>(map.size());
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
decryptedMap.put(key, decryptValue(value));
}
return decryptedMap;
}
/**
* 加密List中每个Map的所有字段
*/
public static List<Map<String, Object>> encryptMapList(List<Map<String, Object>> list) {
if (CollectionUtils.isEmpty(list)) {
return list;
}
List<Map<String, Object>> encryptedList = new ArrayList<>(list.size());
for (Map<String, Object> map : list) {
encryptedList.add(encryptMap(map));
}
return encryptedList;
}
/**
* 解密List中每个Map的所有字段
*/
public static List<Map<String, Object>> decryptMapList(List<Map<String, Object>> list) {
if (CollectionUtils.isEmpty(list)) {
return list;
}
List<Map<String, Object>> decryptedList = new ArrayList<>(list.size());
for (Map<String, Object> map : list) {
decryptedList.add(decryptMap(map));
}
return decryptedList;
}
/**
* 根据值类型进行加密
*/
@SuppressWarnings("unchecked")
private static Object encryptValue(Object value) {
if (value == null) {
return null;
}
if (value instanceof String) {
String strValue = (String) value;
// 已经加密的不再重复加密
if (!strValue.isEmpty() && !strValue.startsWith(Const.ENCRYPTED_PREFIX)) {
return Const.ENCRYPTED_PREFIX + getEncryptionService().encryptAes(strValue);
}
return strValue;
} else if (value instanceof Map) {
// 递归处理嵌套Map
return encryptMap((Map<String, Object>) value);
} else if (value instanceof List) {
// 递归处理List中的每个元素
List<Object> encryptedList = new ArrayList<>();
for (Object item : (List<Object>) value) {
encryptedList.add(encryptValue(item));
}
return encryptedList;
}
// 其他类型保持不变
return value;
}
/**
* 根据值类型进行解密
*/
@SuppressWarnings("unchecked")
private static Object decryptValue(Object value) {
if (value == null) {
return null;
}
if (value instanceof String) {
String strValue = (String) value;
// 对已加密的数据进行解密
if (strValue.startsWith(Const.ENCRYPTED_PREFIX)) {
return getEncryptionService().decryptAes(strValue.substring(Const.ENCRYPTED_PREFIX.length()));
}
return strValue;
} else if (value instanceof Map) {
// 递归处理嵌套Map
return decryptMap((Map<String, Object>) value);
} else if (value instanceof List) {
// 递归处理List中的每个元素
List<Object> decryptedList = new ArrayList<>();
for (Object item : (List<Object>) value) {
decryptedList.add(decryptValue(item));
}
return decryptedList;
}
// 其他类型保持不变
return value;
}
/**
* 判断字段是否为日期类型字段
* @param fieldName 字段名
* @return 是否为日期类型字段
*/
private static boolean isDateField(String fieldName) {
// 检查字段名是否以日期字段前缀开头
for (String prefix : DATE_FIELD_PREFIXES) {
if (fieldName.equals(prefix) || fieldName.endsWith("Time") || fieldName.endsWith("Date")) {
return true;
}
}
return false;
}
}

View File

@ -8,11 +8,14 @@ import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.kakarote.core.common.Const;
import com.kakarote.core.common.FieldEnum;
import com.kakarote.core.common.JxcEnum;
import com.kakarote.core.common.SystemCodeEnum;
import com.kakarote.core.exception.CrmException;
import com.kakarote.core.feign.crm.entity.BiParams;
import com.kakarote.core.security.EncryptionService;
import com.kakarote.core.security.util.EsDataEncryptUtil;
import com.kakarote.core.servlet.ApplicationContextHolder;
import com.kakarote.core.utils.BiTimeUtil;
import com.kakarote.crm.constant.CrmEnum;
@ -249,7 +252,16 @@ public class ElasticUtil {
BulkRequest bulkRequest = new BulkRequest();
ids.forEach(id -> {
Map<String, Object> map = new HashMap<>();
map.put(fieldName, value);
if (value instanceof String) {
String strValue = (String) value;
if (!strValue.isEmpty() && !strValue.startsWith(Const.ENCRYPTED_PREFIX)) {
map.put(fieldName, Const.ENCRYPTED_PREFIX + ApplicationContextHolder.getBean(EncryptionService.class).encryptAes(strValue));
} else {
map.put(fieldName, value);
}
} else {
map.put(fieldName, value);
}
UpdateRequest request = new UpdateRequest(index, "_doc", id.toString());
request.doc(map);
bulkRequest.add(request);
@ -269,8 +281,10 @@ public class ElasticUtil {
*/
public static void updateField(ElasticsearchRestTemplate template, Map<String, Object> map, Integer id, String index) {
try {
// 加密字段值
Map<String, Object> encryptedMap = EsDataEncryptUtil.encryptMap(map);
UpdateRequest request = new UpdateRequest(index, "_doc", id.toString());
request.doc(map);
request.doc(encryptedMap);
template.getClient().update(request, RequestOptions.DEFAULT);
template.refresh(index);
} catch (IOException e) {

View File

@ -26,6 +26,7 @@ import com.kakarote.core.feign.admin.service.AdminService;
import com.kakarote.core.feign.examine.entity.ExamineRecordSaveBO;
import com.kakarote.core.field.FieldService;
import com.kakarote.core.redis.Redis;
import com.kakarote.core.security.util.EsDataEncryptUtil;
import com.kakarote.core.servlet.ApplicationContextHolder;
import com.kakarote.core.servlet.BaseService;
import com.kakarote.core.servlet.upload.FileEntity;
@ -124,8 +125,9 @@ public interface CrmPageService {
}
for (SearchHit hit : hits) {
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
sourceAsMap.put(getLabel().getPrimaryKey(), Integer.valueOf(hit.getId()));
mapList.add(parseMap(sourceAsMap, voList));
Map<String, Object> decryptedMap = EsDataEncryptUtil.decryptMap(sourceAsMap);
decryptedMap.put(getLabel().getPrimaryKey(), Integer.valueOf(hit.getId()));
mapList.add(parseMap(decryptedMap, voList));
}
BasePage<Map<String, Object>> basePage = new BasePage<>();
ApplicationContextHolder.getBean(ICrmRoleFieldService.class).replaceMaskFieldValue(getLabel(),mapList,1);
@ -669,8 +671,12 @@ public interface CrmPageService {
map.put("ownerDeptId",simpleUser.getDeptId());
map.put("ownerDeptName",simpleUser.getDeptName());
}
// 加密所有字段
Map<String, Object> encryptedMap = EsDataEncryptUtil.encryptMap(map);
UpdateRequest request = new UpdateRequest(getIndex(), getDocType(),id.toString());
request.doc(map);
request.doc(encryptedMap);
request.docAsUpsert(true);
try {
getRestTemplate().getClient().update(request, RequestOptions.DEFAULT);