java打印日志时,如何对字段进行脱敏?
原文链接:https://blog.csdn.net/weixin_43901749/article/details/129150818
第一步,创建类继承MessageConverter,重写convert方法,添加注解 @Component("sensitive")
第二步,在logback.xml中增加 conversionRule 标签
在我们开发项目的时候,有些字段比较敏感,比如用户信息,这就需要在打印日志的时候对相关字段脱敏处理,本文提供的脱敏方案是使用conversionRule标签的方式,通过继承MessageConverter,在打印日志的时候对相关字段进行脱敏。
第一步,创建类继承MessageConverter,重写convert方法,如下:
public class SensitiveMessageConverter extends MessageConverter {
/**
* 正则匹配模式
*/
public static final Pattern REGEX_PATTERN = Pattern.compile("\\s*([\"]?[\\w]+[\"]?)(\\s*[:=]+[^\\u4e00-\\u9fa5@,.*{\\[\\w]*\\s*)([\\u4e00-\\u9fa5_\\-@.\\w]+)[\\W&&[^\\-@.]]?\\s*");
@Override
public String convert(ILoggingEvent event) {
// 获取原始日志
String formattedMessage = event.getFormattedMessage();
return doConvert(formattedMessage);
}
private String doConvert(String formattedMessage) {
if (StringUtils.isBlank(formattedMessage)) return formattedMessage;
// 获取是否脱敏开关,可分环境配置是否开启
Boolean convertSwitch = ApolloPropertyUtil.getBooleanProperty("log.sensitive.convert.switch", true);
// 获取需要脱敏的字段。配置模板(key为脱敏模式,value为脱敏字段,可以有多个,other不脱敏):
// {"name":["name","userName"],"mobilePhone":["phone"],"password":["password"],"idCard":["idcard"],"email":["email"],"other":["address"]}
JSONObject jsonObject = ApolloPropertyUtil.getJSONObjectProperty("log.sensitive.convert.fields", "");
// 是否开启脱敏开关
if (!convertSwitch) return formattedMessage;
if (Objects.isNull(jsonObject)) return formattedMessage;
Matcher matcher = REGEX_PATTERN.matcher(formattedMessage);
while (matcher.find()) {
// 字段
String key = matcher.group(1);
key = key.replaceAll("\"", "");
// 字段值
String value = matcher.group(3);
String mode = "";
Iterator<String> iterator = jsonObject.keySet().iterator();
while (iterator.hasNext()) {
String next = iterator.next();
List<String> list = (List<String>) jsonObject.get(next);
if (list.contains(key)) {
// 命中当前属性属于哪一种脱敏模式(只能命中一种),目前支持 phone、password、idcard、other
mode = next;
break;
}
}
// 没有命中脱敏模式,或者属性值为空,或者属性值为”null“,直接返回
if (StringUtils.isAnyBlank(value, mode) || "null".equals(value)) continue;
String afterValue = desensitize(mode, value);
String origin = matcher.group(1) + matcher.group(2) + matcher.group(3);
formattedMessage = formattedMessage.replace(origin, matcher.group(1) + matcher.group(2) + afterValue);
}
return formattedMessage;
}
/**
* 脱敏
*
* @param mode 脱敏模式
* @param value 脱敏的内容
* @return 脱敏后的内容
*/
private String desensitize(String mode, String value) {
SensitiveModeEnum sensitiveModeEnum = SensitiveModeEnum.get(mode);
// 获取不到相关脱敏模式,暂不支持,返回原日志
if (Objects.isNull(sensitiveModeEnum)) return value;
char[] chars = value.toCharArray();
// 具体模式的策略可以再扩展(比如可以支持指定下标范围,指定正则,指定符号前面几位或者后面几位脱敏等等),这里暂不展开
switch (sensitiveModeEnum) {
case NAME:
chars[0] = '*';
break;
case MOBILE_PHONE:
for (int i = 3; i < 7; i++) {
chars[i] = '*';
}
break;
case TELEPHONE:
for (int i = 3; i < 5; i++) {
chars[i] = '*';
}
break;
case ID_CARD:
for (int i = 9; i < 13; i++) {
chars[i] = '*';
}
break;
case PASSWORD:
Arrays.fill(chars, '*');
break;
case EMAIL:
for (int i = 3; i < 6; i++) {
chars[i] = '*';
}
break;
case OTHER:
break;
}
return new String(chars);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
第二步,在logback.xml中增加 conversionRule 标签
conversionWord是输入的日志信息,converterClass对应上面增加的类
<conversionRule conversionWord="msg" converterClass="xxx.xxx.log.SensitiveMessageConverter"/>
- 1
测试
@Test
public void test() {
HashMap<Object, Object> map = new HashMap<>();
Map<String, String> map1 = new HashMap<>();
map1.put("email", "[email protected]");
map1.put("address", "上海市详细地址");
map.put("name", "张三分");
map.put("sendPhone", "18912430987");
map.put("password", "123456");
map.put("detail", map1);
log.info("结果:{}", JSON.toJSONString(map));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
结果:
结果:{"password":"******","name":"*三分","sendPhone":"189****0987","detail":{"address":"上海市详细地址","email":"123***[email protected]"}}
- 1