如何在Spring Boot 3中扩展Log4j以拦截日志参数并隐藏敏感数据?
实现方案:自定义Log4j参数转换器完成脱敏
1. 编写自定义脱敏转换器
创建一个继承LogEventPatternConverter的类,作为Log4j的扩展插件,负责识别并处理敏感参数:
import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.pattern.ConverterKeys; import org.apache.logging.log4j.core.pattern.LogEventPatternConverter; import org.apache.logging.log4j.core.pattern.PatternConverter; @Plugin(name = "SensitiveDataConverter", category = PatternConverter.CATEGORY) @ConverterKeys({"sensitive"}) public class SensitiveDataConverter extends LogEventPatternConverter { protected SensitiveDataConverter(String[] options) { super("SensitiveData", "sensitive"); } public static SensitiveDataConverter newInstance(String[] options) { return new SensitiveDataConverter(options); } @Override public void format(LogEvent event, StringBuilder toAppendTo) { Object[] params = event.getMessage().getParameters(); if (params == null || params.length == 0) { toAppendTo.append(event.getMessage().getFormattedMessage()); return; } Object[] processedParams = new Object[params.length]; for (int i = 0; i < params.length; i++) { processedParams[i] = maskSensitive(params[i]); } String format = event.getMessage().getFormat(); toAppendTo.append(String.format(format, processedParams)); } private Object maskSensitive(Object param) { if (param == null) return null; String value = param.toString(); // 手机号脱敏:前3后4保留,中间替换为**** if (value.matches("1[3-9]\\d{9}")) { return value.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"); } // 身份证脱敏:前6后4保留,中间替换为******** if (value.matches("\\d{17}[\\dXx]")) { return value.replaceAll("(\\d{6})\\d{8}(\\d{4}[\\dXx])", "$1********$2"); } // 密码直接替换为****** if (value.length() >= 6 || value.contains("password")) { // 可根据实际情况调整判断逻辑 return "******"; } // 其他敏感规则可在此扩展,比如银行卡号、邮箱等 return value; } }
2. 修改Log4j配置文件
在项目的log4j2.xml中,将默认的消息输出格式替换为自定义的sensitive转换器:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="INFO"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <!-- 用%sensitive替代原来的%msg --> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %sensitive%n"/> </Console> </Appenders> <Loggers> <Root level="info"> <AppenderRef ref="Console"/> </Root> </Loggers> </Configuration>
3. 测试脱敏效果
写个简单的接口测试日志输出:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { private static final Logger logger = LoggerFactory.getLogger(TestController.class); @GetMapping("/test") public String testSensitiveLog() { String phone = "13987654321"; String idCard = "310101198510101234"; String password = "mySecurePwd123"; logger.info("用户登录:手机号={}, 身份证={}, 密码={}", phone, idCard, password); return "测试完成"; } }
启动项目调用接口后,控制台输出的日志会自动脱敏:
2024-05-20 15:10:30.456 [http-nio-8080-exec-1] INFO com.example.demo.TestController - 用户登录:手机号=139****4321, 身份证=310101**1234, 密码=
额外说明
- 脱敏规则可以根据业务需求自由扩展,比如添加银行卡号
\\d{16,19}的脱敏逻辑。 - 如果需要动态配置脱敏规则,可以把规则定义在
application.yml中,通过Spring的配置类注入到转换器里。 - Spring Boot 3默认集成Log4j 2.x,不需要额外引入依赖,直接使用即可。
内容的提问来源于stack exchange,提问作者Marco
相关产品推荐
相关产品推荐

