做个网站要钱吗全国广告投放平台
一、需求场景:为什么需要脱敏框架?
在数据安全合规要求下,敏感信息处理成为系统必备能力。典型场景:
- 用户隐私保护(手机号、身份证、邮箱等)
- 日志敏感信息过滤
- 接口返回数据自动脱敏
传统方案痛点:
- 硬编码脱敏逻辑,维护成本高
- 不同字段需重复编写相似代码
- 无法动态调整脱敏规则
二、框架设计全景图
三、核心实现三步走
1. 注解体系设计(声明式配置)
顶级脱敏注解
@Documented
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside // 此注解是其他所有 jackson 注解的元注解,打上了此注解的注解表明是 jackson 注解的一部分
@JsonSerialize(using = StringDesensitizeSerializer.class) // 指定序列化器
public @interface DesensitizeBy {/*** 脱敏处理器*/@SuppressWarnings("rawtypes")Class<? extends DesensitizationHandler> handler();}
邮箱脱敏注解
@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@DesensitizeBy(handler = EmailDesensitizationHandler.class)
public @interface EmailDesensitize {/*** 匹配的正则表达式*/String regex() default "(^.)[^@]*(@.*$)";/*** 替换规则,邮箱;** 比如:example@gmail.com 脱敏之后为 e****@gmail.com*/String replacer() default "$1****$2";/*** 是否禁用脱敏** 支持 Spring EL 表达式,如果返回 true 则跳过脱敏*/String disable() default "";}
2. 处理机制实现(策略模式+模板方法模式)
脱敏处理器
public interface DesensitizationHandler<T extends Annotation> {/*** 脱敏** @param origin 原始字符串* @param annotation 注解信息* @return 脱敏后的字符串*/String desensitize(String origin, T annotation);/*** 是否禁用脱敏的 Spring EL 表达式** 如果返回 true 则跳过脱敏** @param annotation 注解信息* @return 是否禁用脱敏的 Spring EL 表达式*/default String getDisable(T annotation) {// 约定:默认就是 enable() 属性。如果不符合,子类重写try {return (String) ReflectUtil.invoke(annotation, "disable");} catch (Exception ex) {return "";}}}
正则表达式脱敏处理器抽象类(模板方法模式+策略模式)
public abstract class AbstractRegexDesensitizationHandler<T extends Annotation>implements DesensitizationHandler<T> {
//==========================================不可变部分即公共方法即模板方法模式的实现===========================@Overridepublic String desensitize(String origin, T annotation) {// 1. 判断是否禁用脱敏Object disable = SpringExpressionUtils.parseExpression(getDisable(annotation));if (Boolean.TRUE.equals(disable)) {return origin;}// 2. 执行脱敏String regex = getRegex(annotation);String replacer = getReplacer(annotation);return origin.replaceAll(regex, replacer);}//==========================================可变部分抽象由具体子类实现===========================/*** 获取注解上的 regex 参数** @param annotation 注解信息* @return 正则表达式*/abstract String getRegex(T annotation);/*** 获取注解上的 replacer 参数** @param annotation 注解信息* @return 待替换的字符串*/abstract String getReplacer(T annotation);}
EmailDesensitize的脱敏处理器
//==========================================邮箱脱敏策略===========================public class EmailDesensitizationHandler extends AbstractRegexDesensitizationHandler<EmailDesensitize> {@OverrideString getRegex(EmailDesensitize annotation) {return annotation.regex();}@OverrideString getReplacer(EmailDesensitize annotation) {return annotation.replacer();}}
3. Jackson序列化集成
脱敏序列化器
public class StringDesensitizeSerializer extends StdSerializer<String> implements ContextualSerializer {@Getter@Setterprivate DesensitizationHandler desensitizationHandler;protected StringDesensitizeSerializer() {super(String.class);}@Overridepublic JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) {DesensitizeBy annotation = beanProperty.getAnnotation(DesensitizeBy.class);if (annotation == null) {return this;}// 创建一个 StringDesensitizeSerializer 对象,使用 DesensitizeBy 对应的处理器StringDesensitizeSerializer serializer = new StringDesensitizeSerializer();serializer.setDesensitizationHandler(Singleton.get(annotation.handler()));return serializer;}@Override@SuppressWarnings("unchecked")public void serialize(String value, JsonGenerator gen, SerializerProvider serializerProvider) throws IOException {if (StrUtil.isBlank(value)) {gen.writeNull();return;}// 获取序列化字段Field field = getField(gen);// 自定义处理器DesensitizeBy[] annotations = AnnotationUtil.getCombinationAnnotations(field, DesensitizeBy.class);if (ArrayUtil.isEmpty(annotations)) {gen.writeString(value);return;}for (Annotation annotation : field.getAnnotations()) {if (AnnotationUtil.hasAnnotation(annotation.annotationType(), DesensitizeBy.class)) {value = this.desensitizationHandler.desensitize(value, annotation);gen.writeString(value);return;}}gen.writeString(value);}/*** 获取字段** @param generator JsonGenerator* @return 字段*/private Field getField(JsonGenerator generator) {String currentName = generator.getOutputContext().getCurrentName();Object currentValue = generator.getCurrentValue();Class<?> currentValueClass = currentValue.getClass();return ReflectUtil.getField(currentValueClass, currentName);}}
四、使用示例:三步完成脱敏
1. 添加注解
public class UserVO {@EmailDesensitize(replacer = "$1***$2") // 自定义替换规则private String email;@PhoneDesensitize // 使用默认手机号脱敏规则private String phone;
}
2. 返回结果对比
// 原始数据
{"email": "test@example.com","phone": "13812345678"
}// 脱敏后
{"email": "t***@example.com","phone": "138****5678"
}
3. 动态关闭脱敏(SpEL支持)
@EmailDesensitize(disable = "${app.desensitize.disable:false}")
private String email;
五、设计亮点分析
1. 开闭原则实践
- 新增类型:只需添加注解+处理器
- 修改规则:调整注解参数即可
2. 性能优化点
- 单例模式:处理器全局单例复用
- 缓存机制:注解解析结果缓存
- 懒加载:按需初始化处理器
3. 灵活配置能力
// 多规则叠加示例
@EmailDesensitize(regex = "(?<=.{2}).", replacer = "*")
@ConditionalOnProperty("security.enabled")
private String email;