springboot_log4j2_日志脱敏
@Plugin(name = "MaskSensitiveDataPolicy", category = Core.CATEGORY_NAME,
elementType = "rewritePolicy", printObject = true)
public class MaskSensitiveDataPolicy implements RewritePolicy {
private static final Logger LOGGER = LoggerFactory.getLogger(MaskSensitiveDataPolicy.class);
private String[] sensitiveClasses;
private volatile boolean encryptEnable; //这里最好通过开关控制一下功能是否开和关
public static final Map<String, DesensitizedUtil.DesensitizedType> SENSITIVE_MAP = new HashMap<>();
static {
//DesensitizedUtil 这里引用的是hutools
SENSITIVE_MAP.put("username", DesensitizedUtil.DesensitizedType.CHINESE_NAME);
SENSITIVE_MAP.put("password", DesensitizedUtil.DesensitizedType.PASSWORD);
SENSITIVE_MAP.put("cellphone", DesensitizedUtil.DesensitizedType.MOBILE_PHONE);
SENSITIVE_MAP.put("email", DesensitizedUtil.DesensitizedType.EMAIL);
}
@PluginFactory
public static MaskSensitiveDataPolicy createPolicy(
@PluginElement("sensitive") final String[] sensitiveClasses) {
return new MaskSensitiveDataPolicy(sensitiveClasses);
}
private MaskSensitiveDataPolicy(String[] sensitiveClasses) {
super();
encryptEnable = Boolean.parseBoolean(System.getProperty(""));
this.sensitiveClasses = sensitiveClasses;
}
@Override
public LogEvent rewrite(LogEvent event) {
Message rewritten = rewriteIfSensitive(event.getMessage());
if (rewritten != event.getMessage()) {
return new Log4jLogEvent.Builder(event).setMessage(rewritten).build();
}
return event;
}
private Message rewriteIfSensitive(Message message) {
// 确保已经通过设置系统属性`` 为 `false`关闭了garbage-free logging
// 否则可能传入ReusableObjectMessage, ReusableParameterizedMessage或
// MutableLogEvent messages 导致不能重写。
// Make sure to switch off garbage-free logging
// by setting system property `` to `false`.
// Otherwise you may get ReusableObjectMessage, ReusableParameterizedMessage
// or MutableLogEvent messages here which may not be rewritable...
if (message instanceof ObjectMessage) {
return rewriteObjectMessage((ObjectMessage) message);
}
if (message instanceof ParameterizedMessage) {
return rewriteParameterizedMessage((ParameterizedMessage) message);
}
return message;
}
private Message rewriteObjectMessage(ObjectMessage message) {
SensitiveStrategy sensitive = isSensitive(message.getParameter());
if (encryptEnable && sensitive.coincidence()) {
return new ObjectMessage(sensitive.strategy(message.getParameter()));
}
return message;
}
private Message rewriteParameterizedMessage(ParameterizedMessage message) {
Object[] params = message.getParameters();
boolean changed = rewriteSensitiveParameters(params);
return changed && encryptEnable ? new ParameterizedMessage(message.getFormat(), params) : message;
}
private boolean rewriteSensitiveParameters(Object[] params) {
boolean changed = false;
for (int i = 0; i < params.length; i++) {
SensitiveStrategy sensitive = isSensitive(params[i]);
if (sensitive.coincidence()) {
params[i] = sensitive.strategy(params[i]);
changed = true;
}
}
return changed;
}
private SensitiveStrategy isSensitive(Object parameter) {
SensitiveStrategy defaultStrategy = new SensitiveStrategy() {
@Override
public boolean coincidence() {
return false;
}
@Override
public Object strategy(Object params) {
return null;
}
};
if (null == parameter) return defaultStrategy;
// TODo 加入缓存
LogEncryptClz logEncryptClz = parameter.getClass().getAnnotation(LogEncryptClz.class);
boolean objInfer = null != logEncryptClz && logEncryptClz.enable() && parameter.getClass().getPackage().getName().startsWith("com.你的包名");
if (objInfer) {
return new ObjectSensitiveStrategy(true);
}
if (parameter instanceof List) {
return new ListSensitiveStrategy(true);
}
return defaultStrategy;
}
public interface SensitiveStrategy {
boolean coincidence();
Object strategy(Object params);
}
public static class ObjectSensitiveStrategy implements SensitiveStrategy {
private final boolean coincidence;
public ObjectSensitiveStrategy(boolean coincidence) {
this.coincidence = coincidence;
}
@Override
public boolean coincidence() {
return this.coincidence;
}
@Override
public Object strategy(Object parameter) {
if (null == parameter) {
return null;
}
return objectStrategy(parameter);
}
public static Object objectStrategy(Object parameter) {
JSONObject json = (JSONObject) JSONObject.toJSON(parameter);
Map<String, Field> fileNameMaps = Stream.of(ReflectUtil.getFields(parameter.getClass())).filter(field -> {
return field.isAnnotationPresent(LogEncryptFiled.class);
}).collect(Collectors.toMap(Field::getName, Function.identity(), (a, b) -> b));
if (MapUtil.isEmpty(fileNameMaps)) {
return parameter;
}
for (String key : json.keySet()) {
Object v = json.get(key);
if (null == v || !fileNameMaps.containsKey(key)) {
continue;
}
Field field = fileNameMaps.get(key);
LogEncryptFiled annotation = field.getAnnotation(LogEncryptFiled.class);
DesensitizedUtil.DesensitizedType desensitizedType = annotation.type();
try {
json.put(key, DesensitizedUtil.desensitized(String.valueOf(json.get(key)), desensitizedType));
} catch (Exception exception) {
LOGGER.error("【数据脱敏】处理脱敏数据异常 源数据={}", json, exception);
}
}
return JSONObject.toJSON(json);
}
}
public static class ListSensitiveStrategy implements SensitiveStrategy {
private final boolean coincidence;
public ListSensitiveStrategy(boolean coincidence) {
this.coincidence = coincidence;
}
@Override
public boolean coincidence() {
return this.coincidence;
}
@Override
public Object strategy(Object parameter) {
if (null == parameter) {
return null;
}
List list = (List) parameter;
if (CollUtil.isEmpty(list)) return null;
List result = new ArrayList();
for (Object o : list) {
LogEncryptClz annotation = o.getClass().getAnnotation(LogEncryptClz.class);
if (null == annotation || !annotation.enable() || !o.getClass().getPackage().getName().startsWith("com.你的包名")) {
continue;
}
if (o instanceof List) {
result.add(strategy(o));
continue;
}
result.add(ObjectSensitiveStrategy.objectStrategy(o));
}
return result;
}
}
}