You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot项目中基于log4j2通过注解实现DTO敏感字段日志脱敏咨询

Spring Boot + Log4j2 日志场景专属敏感字段脱敏实现方案

核心思路是替换Log4j2默认的消息工厂,在日志参数被转为字符串前拦截原始对象,仅针对日志打印场景执行脱敏处理,不影响业务层的序列化、对象操作逻辑。

1. 定义敏感字段标记注解

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Sensitive {
    // 需要脱敏的字段名
    String[] fields() default {};
}

使用方式和你给出的示例一致:

@Sensitive(fields = {"password", "email"})
public class MyDTO {
    private String name;
    private String email;
    private String password;
    // 省略getter/setter
}

2. 实现脱敏工具类

处理时会创建对象副本,不会修改原对象的属性值,避免影响业务逻辑:

import org.springframework.beans.BeanUtils;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;

public class SensitiveUtils {
    public static Object handleSensitive(Object obj) {
        if (obj == null) return null;
        Class<?> clazz = obj.getClass();
        // 没有标注@Sensitive注解直接返回原对象
        if (!clazz.isAnnotationPresent(Sensitive.class)) {
            return obj;
        }
        try {
            // 创建对象副本,避免修改原对象
            Object copyObj = clazz.getDeclaredConstructor().newInstance();
            BeanUtils.copyProperties(obj, copyObj);
            Sensitive sensitiveAnno = clazz.getAnnotation(Sensitive.class);
            List<String> sensitiveFields = Arrays.asList(sensitiveAnno.fields());
            // 替换敏感字段值
            for (String fieldName : sensitiveFields) {
                Field field = clazz.getDeclaredField(fieldName);
                field.setAccessible(true);
                Object value = field.get(copyObj);
                if (value instanceof String strVal) {
                    // 可根据字段类型自定义脱敏规则,比如邮箱保留前缀1位和@后缀,密码全替换为***
                    if (fieldName.equals("email")) {
                        int atIndex = strVal.indexOf("@");
                        if (atIndex > 1) {
                            field.set(copyObj, strVal.charAt(0) + "***" + strVal.substring(atIndex));
                        } else {
                            field.set(copyObj, "***");
                        }
                    } else if (fieldName.equals("password")) {
                        field.set(copyObj, "***");
                    } else {
                        // 默认脱敏规则:保留前1后1,中间替换为***
                        if (strVal.length() <= 2) {
                            field.set(copyObj, "***");
                        } else {
                            field.set(copyObj, strVal.charAt(0) + "***" + strVal.charAt(strVal.length()-1));
                        }
                    }
                }
            }
            return copyObj;
        } catch (Exception e) {
            // 脱敏异常直接返回原对象,避免影响日志打印
            return obj;
        }
    }
}

3. 自定义Log4j2消息工厂

替换默认的参数化消息工厂,在生成日志消息前先处理所有参数的敏感字段:

import org.apache.logging.log4j.message.AbstractMessageFactory;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.ParameterizedMessage;

public class SensitiveMessageFactory extends AbstractMessageFactory {
    @Override
    public Message newMessage(String message, Object... params) {
        if (params == null || params.length == 0) {
            return new ParameterizedMessage(message, params);
        }
        // 遍历所有日志参数,处理敏感字段
        Object[] handledParams = new Object[params.length];
        for (int i = 0; i < params.length; i++) {
            handledParams[i] = SensitiveUtils.handleSensitive(params[i]);
        }
        return new ParameterizedMessage(message, handledParams);
    }
}

4. 配置Log4j2使用自定义消息工厂

在你的log4j2.xml配置文件的根标签<Configuration>上添加messageFactory属性指定自定义工厂类即可:

<Configuration status="warn" messageFactory="com.yourpackage.SensitiveMessageFactory">
    <!-- 其余原有配置保持不变 -->
    <Appenders>
        ...
    </Appenders>
    <Loggers>
        ...
    </Loggers>
</Configuration>

方案优势

  • 仅在日志打印场景触发脱敏,不会影响业务层的JSON序列化、对象原生toString()调用
  • 日志参数还未转为字符串时就完成脱敏,能直接拿到原始对象的注解配置
  • 无侵入性,原有日志打印代码不需要做任何修改

内容的提问来源于stack exchange,提问作者Eugene

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 10:57:04