springboot数据动态脱敏
public class DesensitizeSerializer extends JsonSerializer<String> implements ContextualSerializer {
/**
* 脱敏规则
*/
private DesensitizeRuleEnum rule;
private String condition; // SpEL 表达式
private BeanProperty property; // 当前字段属性
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
Object currentObject = getCurrentObject(gen); // 获取当前对象
boolean shouldMask = evaluateCondition(currentObject);
if (shouldMask) {
// 条件满足时脱敏
gen.writeString(rule.function().apply(value));
} else {
// 条件不满足时保留原值
gen.writeString(value);
}
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
//获取对象属性上的自定义注解
CustomSerializer annotation = property.getAnnotation(CustomSerializer.class);
if (annotation != null && String.class == property.getType().getRawClass()) {
DesensitizeSerializer serializer = new DesensitizeSerializer();
serializer.rule = annotation.function();
// 注入条件表达式
serializer.condition = annotation.condition();
serializer.property = property;
return serializer;
}
return prov.findValueSerializer(property.getType(), property);
}
private boolean evaluateCondition(Object target) {
if (StringUtils.isEmpty(condition)) {
return true; // 无条件默认脱敏
}
try {
// 创建SpEL解析器
ExpressionParser parser = new SpelExpressionParser();
// 设置上下文(target是被序列化的对象)
EvaluationContext context = new StandardEvaluationContext(target);
// 执行表达式并返回布尔结果
return Boolean.TRUE.equals(parser.parseExpression(condition).getValue(context, Boolean.class));
} catch (Exception e) {
log.warn("脱敏条件表达式执行失败: {}", condition, e);
return false; // 表达式错误时不脱敏
}
}
private Object getCurrentObject(JsonGenerator gen) {
try {
// 获取序列化器上下文中的输出层(底层为 BeanSerializer)
Object outputContext = gen.getOutputContext();
if (outputContext instanceof JsonWriteContext) {
JsonWriteContext context = (JsonWriteContext) outputContext;
// 通过反射获取当前对象实例
Field currentValueField = JsonWriteContext.class.getDeclaredField("_currentValue");
currentValueField.setAccessible(true);
return currentValueField.get(context);
}
} catch (Exception e) {
log.warn("无法获取当前对象", e);
}
return null;
}
}