53 lines
2.0 KiB
Java
53 lines
2.0 KiB
Java
package com.baiyue.common.audit;
|
|||
|
|
|
||
|
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||
|
|
import com.fasterxml.jackson.databind.JsonNode;
|
||
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||
|
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||
|
|
|
||
|
|
import java.util.Iterator;
|
||
|
|
import java.util.Locale;
|
||
|
|
import java.util.Map;
|
||
|
|
import java.util.Set;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 审计数据脱敏器,在记录请求快照前递归屏蔽密码、令牌、密钥等敏感字段。
|
||
|
|
*/
|
||
|
|
public class SensitiveDataSanitizer {
|
||
|
|
private static final Set<String> SENSITIVE = Set.of("password", "passwordhash", "token", "accesstoken",
|
||
|
|
"refreshtoken", "authorization", "secret", "idcard", "bankcard", "mobile", "phone", "email");
|
||
|
|
private final ObjectMapper mapper;
|
||
|
|
private final int maxLength;
|
||
|
|
|
||
|
|
public SensitiveDataSanitizer(ObjectMapper mapper, int maxLength) {
|
||
|
|
this.mapper = mapper;
|
||
|
|
this.maxLength = maxLength;
|
||
|
|
}
|
||
|
|
|
||
|
|
public String sanitize(Object value) {
|
||
|
|
if (value == null) return null;
|
||
|
|
try {
|
||
|
|
JsonNode root = mapper.valueToTree(value);
|
||
|
|
redact(root);
|
||
|
|
String json = mapper.writeValueAsString(root);
|
||
|
|
return json.length() <= maxLength ? json : json.substring(0, maxLength) + "...[truncated]";
|
||
|
|
} catch (IllegalArgumentException | JsonProcessingException e) {
|
||
|
|
return "\"[unserializable]\"";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void redact(JsonNode node) {
|
||
|
|
if (node == null) return;
|
||
|
|
if (node.isObject()) {
|
||
|
|
Iterator<Map.Entry<String, JsonNode>> fields = node.fields();
|
||
|
|
while (fields.hasNext()) {
|
||
|
|
Map.Entry<String, JsonNode> field = fields.next();
|
||
|
|
String normalized = field.getKey().replace("_", "").toLowerCase(Locale.ROOT);
|
||
|
|
if (SENSITIVE.stream().anyMatch(normalized::contains)) {
|
||
|
|
((ObjectNode) node).put(field.getKey(), "******");
|
||
|
|
} else redact(field.getValue());
|
||
|
|
}
|
||
|
|
} else if (node.isArray()) node.forEach(this::redact);
|
||
|
|
}
|
||
|
|
}
|