SpringBoot 敏感信息脱敏
1、定义脱敏注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
@JacksonAnnotation
public @interface Desensitization {
/**
* 字段脱敏策略
* @return
*/
DesensitizationStrategy strategy();
/**
* 匹配正则表达式
* <pre>
* 1. 手机号:regex:(\\d{3})\\d{4}(\\d{4}) ,replacement: $1****$2
* 2. 地址:regex:(\\S{3})\\S{2}(\\S*)\\S{2},replacement:$1****$2****
* </pre>
* @return String
*/
String regex() default "";
/**
* 替换内容
* @return String
*/
String replacement() default "";
}
脱敏策略
/**
* 脱敏策略
*/
public enum DesensitizationStrategy {
/**
* 用户ID
* 例如: 100 -> 0
*/
USER_ID,
/**
* 中文名称
* 如:段正淳 -> 段**
*/
CHINESE_NAME,
/**
* 身份证号
* 如:51343620000320711X -> 5***************1X
*/
ID_CARD,
/**
* 座机号
* 如:09157518479 -> 0915*****79
*/
FIXED_PHONE,
/**
* 手机号
* 如:18049531999 -> 180****1999
*/
MOBILE_PHONE,
/**
* 地址:北京市海淀区马连洼街道289号
* 北京市海淀区马********
*/
ADDRESS,
/**
* 电子邮件
* 如:duandazhi-jack@gmail.com.cn -> d*************@gmail.com.cn
*/
EMAIL,
/**
* 密码
* 如: 1234567890 -> **********
*/
PASSWORD,
/**
* 中国大陆车牌,包含普通车辆、新能源车辆
* 如:苏D40000 -> 苏D4***0
*/
CAR_LICENSE,
/**
* 银行卡
* 11011111222233333256 -> 1101 **** **** **** 3256
*/
BANK_CARD;
}
jackson 支持注解脱敏
package com.aimilin.common.security.json;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.serializer.ValueFilter;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.aimilin.common.core.annotation.Desensitization;
import com.aimilin.common.core.enums.DesensitizationStrategy;
import com.aimilin.common.core.utils.DesensitizedUtil;
import org.apache.commons.lang3.RegExUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
* 脱敏序列化
* <pre>
* 1、fastjson 使用,直接 JSON.toJSONString(object,new DesensitizationSerializer());
* 2、jackson使用,com.aimilin.common.core.utils.JsonUtil#toJson(java.lang.Object)
* </pre>
* @author liujunguang1
* @version V1.0
* @date 2022/9/6 14:27
*/
public class DesensitizationSerializer extends JsonSerializer<Object> implements ValueFilter {
/**
* 脱敏配置项
*/
private Desensitization desensitization;
/**
* fastjson序列化缓存
*/
private static final Map<Class<?>, Map<String,Desensitization>> map = new ConcurrentHashMap<>();
public DesensitizationSerializer() {
}
public DesensitizationSerializer(Desensitization desensitization) {
this.desensitization = desensitization;
}
/**
* Method that can be called to ask implementation to serialize
* values of type this serializer handles.
*
* @param value Value to serialize; can <b>not</b> be null.
* @param gen Generator used to output resulting Json content
* @param serializers Provider that can be used to get serializers for
* serializing Objects value contains, if any.
*/
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if(Objects.isNull(value) || Objects.isNull(desensitization)) {
serializers.defaultSerializeValue(value, gen);
return;
}
gen.writeString(this.desensitized(value));
}
/**
* 将字段信息脱敏
* @param value 当前值
* @return 结果
*/
private String desensitized(Object value) {
String valueStr = StrUtil.toStringOrNull(value);
DesensitizationStrategy strategy = this.desensitization.strategy();
if(Objects.nonNull(strategy)){
return DesensitizedUtil.desensitized(valueStr, DesensitizedUtil.DesensitizedType.valueOf(strategy.name()));
}
if(StringUtils.isNotBlank(this.desensitization.regex())) {
return RegExUtils.replaceAll(valueStr, this.desensitization.regex(), this.desensitization.replacement());
}
return valueStr;
}
@Override
public Object process(Object object, String name, Object value) {
if (null == object || StringUtils.isEmpty(name) || null == value){
return value;
}
Desensitization annotation = this.getFieldDesensitization(object, name);
if(annotation != null){
return new DesensitizationSerializer(annotation).desensitized(value);
}
return value;
}
/**
* 获取属性对应的Desensitization的注解
* @param object 对象
* @param name 属性名称
* @return 结果
*/
private Desensitization getFieldDesensitization(Object object, String name) {
Class<?> key = object.getClass();
if(map.containsKey(key)){
return map.get(key).get(name);
}
Field[] fields = ReflectUtil.getFields(key);
Map<String,Desensitization> fieldMap = new HashMap<>();
for (Field field: fields){
Desensitization annotation = field.getAnnotation(Desensitization.class);
if(annotation != null) {
fieldMap.put(field.getName(), annotation);
}
}
map.put(key, fieldMap);
return map.get(key).get(name);
}
}
jackson Bean序列化
package com.aimilin.common.security.json;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.aimilin.common.core.annotation.Desensitization;
import java.util.List;
/**
* Jackson字段脱敏序列化工具
*
* @author liujunguang1
* @version V1.0
* @date 2022/9/6 17:23
*/
public class DesensitizationSerializerModifier extends BeanSerializerModifier{
/**
* Method called by {@link BeanSerializerFactory} with tentative set
* of discovered properties.
* Implementations can add, remove or replace any of passed properties.
* <p>
* Properties <code>List</code> passed as argument is modifiable, and returned List must
* likewise be modifiable as it may be passed to multiple registered
* modifiers.
*
* @param config 配置
* @param beanDesc 定义
* @param beanProperties 属性
*/
@Override
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
for (BeanPropertyWriter beanProperty : beanProperties) {
Desensitization desensitization = beanProperty.getAnnotation(Desensitization.class);
if (desensitization != null) {
beanProperty.assignSerializer(new DesensitizationSerializer(desensitization));
}
}
return beanProperties;
}
}
3 注册序列化器
@Bean
public Jackson2ObjectMapperBuilderCustomizer desensitizationJackson2ObjectMapperBuilderCustomizer(){
return jacksonObjectMapperBuilder -> {
SimpleModule simpleModule = new SimpleModule();
simpleModule.setSerializerModifier(new DesensitizationSerializerModifier());
List<Module> moduleList = new ArrayList<>();
moduleList.add(simpleModule);
// 支持多个配置信息
jacksonObjectMapperBuilder.modules(moduleList::addAll);
jacksonObjectMapperBuilder.modules(moduleList);
};
}
敏感信息脱敏
由于数据转换成JSON字符串都是采用的jackson
- jackson 信息脱敏
在java类中添加注解:com.jd.gxf.common.core.annotation.Desensitization
该注解支持预定义脱敏模式与自定义脱敏格式
@Data
public class SysUserResult {
/**
* 主键
*/
private Long id;
/**
* 姓名
*/
private String name;
/**
* 邮箱
*/
@Desensitization(strategy = DesensitizationStrategy.EMAIL)
private String email;
/**
* 手机
*/
@Desensitization(strategy = DesensitizationStrategy.MOBILE_PHONE)
private String phone;
}
- Fastjson使用说明
JSON.toJsonString(sysUserResult, new DesensitizationSerializer())