<dependency>
<groupId>cn.hutoolgroupId>
<artifactId>hutool-allartifactId>
<version>5.7.5version>
dependency>
package com.kang.mongodb.annotation;
import cn.hutool.core.util.DesensitizedUtil;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Sensitive {
/**
* 脱敏作用的类型
* @return
*/
DesensitizedUtil.DesensitizedType type();
}
@Sensitive(type = DesensitizedUtil.DesensitizedType.MOBILE_PHONE)
private String phone;
package com.kang.mongodb.utils;
import cn.hutool.core.util.DesensitizedUtil;
import com.kang.mongodb.annotation.Sensitive;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.UnaryOperator;
/**
* 脱敏工具类
*/
@Slf4j
public class SensitiveUtil {
private static final Map<String, UnaryOperator<String>> desensitizeMap = new ConcurrentHashMap<>();
static {
for (DesensitizedUtil.DesensitizedType type : DesensitizedUtil.DesensitizedType.values()) {
desensitizeMap.put(type.name(), originalValue -> DesensitizedUtil.desensitized(originalValue, type));
}
}
/**
* 这里可以使用遍历DesensitizedUtil.DesensitizedType的方式进行初始化,
* 但是为了以后维护拓展观察方便,就不再使用遍历的方式,手动维护初始化
*/
// static {
// // 用户ID
// desensitizeMap.put(DesensitizedUtil.DesensitizedType.USER_ID.name(), originalValue -> DesensitizedUtil.desensitized(originalValue, DesensitizedUtil.DesensitizedType.USER_ID));
// // 中文名
// desensitizeMap.put(DesensitizedUtil.DesensitizedType.CHINESE_NAME.name(), originalValue -> DesensitizedUtil.desensitized(originalValue, DesensitizedUtil.DesensitizedType.CHINESE_NAME));
// // 身份证号
// desensitizeMap.put(DesensitizedUtil.DesensitizedType.ID_CARD.name(), originalValue -> DesensitizedUtil.desensitized(originalValue, DesensitizedUtil.DesensitizedType.ID_CARD));
// // 座机号
// desensitizeMap.put(DesensitizedUtil.DesensitizedType.FIXED_PHONE.name(), originalValue -> DesensitizedUtil.desensitized(originalValue, DesensitizedUtil.DesensitizedType.FIXED_PHONE));
// // 手机号
// desensitizeMap.put(DesensitizedUtil.DesensitizedType.MOBILE_PHONE.name(), originalValue -> DesensitizedUtil.desensitized(originalValue, DesensitizedUtil.DesensitizedType.MOBILE_PHONE));
// // 地址
// desensitizeMap.put(DesensitizedUtil.DesensitizedType.ADDRESS.name(), originalValue -> DesensitizedUtil.desensitized(originalValue, DesensitizedUtil.DesensitizedType.ADDRESS));
// // 电子邮件
// desensitizeMap.put(DesensitizedUtil.DesensitizedType.EMAIL.name(), originalValue -> DesensitizedUtil.desensitized(originalValue, DesensitizedUtil.DesensitizedType.EMAIL));
// // 密码
// desensitizeMap.put(DesensitizedUtil.DesensitizedType.PASSWORD.name(), originalValue -> DesensitizedUtil.desensitized(originalValue, DesensitizedUtil.DesensitizedType.PASSWORD));
// // 中国大陆车牌,包含普通车辆、新能源车辆
// desensitizeMap.put(DesensitizedUtil.DesensitizedType.CAR_LICENSE.name(), originalValue -> DesensitizedUtil.desensitized(originalValue, DesensitizedUtil.DesensitizedType.CAR_LICENSE));
// // 银行卡
// desensitizeMap.put(DesensitizedUtil.DesensitizedType.BANK_CARD.name(), originalValue -> DesensitizedUtil.desensitized(originalValue, DesensitizedUtil.DesensitizedType.BANK_CARD));
// }
/**
* 脱敏方法
* @param obj
* @param
* @return
*/
public static <T> T desensitize(T obj) {
if (obj == null) {
return null;
}
// 利用反射完成注解修饰字段的脱敏
Class<?> clazz = obj.getClass();
// 获得类的所有属性,包括private声明的和继承类
Field[] fields = clazz.getDeclaredFields();
// 遍历所有的属性字段
for (Field field : fields) {
// 判断该类Sensitive中的字段是否声明了指定注解。
if (field.isAnnotationPresent(Sensitive.class)) {
// 启动或禁用访问安全检查的开关
field.setAccessible(true);
try {
// 获取注解中的脱敏方式
Sensitive annotation = field.getAnnotation(Sensitive.class);
// 如果获取不到脱敏方式,或者脱敏方式为空,不做脱敏操作,返回元数据
if (Objects.isNull(annotation) || Objects.isNull(annotation.type()) || Objects.isNull(desensitizeMap.get(annotation.type().name()))) {
log.info("脱敏方式未配置,当前字段:{}不执行任何脱敏操做", field.getName());
continue;
}
// 从注解中获取配置的脱敏方式
String type = annotation.type().name();
// 获取字段的值
Object value = field.get(obj);
if (!(value instanceof String)) {
log.info("非String类型的数据暂不支持数据脱敏");
return obj;
}
// String类型的值
// 原始值
String originalValue = (String) value;
// 自定义加工后的值
UnaryOperator<String> operator = desensitizeMap.get(type);
// 获取脱敏后的值
String desensitizedValue = operator.apply(originalValue);
// 重新赋值
field.set(obj, desensitizedValue);
log.info("当前字段:{},脱敏前的值:{},脱敏后的值:{}", field.getName(), originalValue, desensitizedValue);
} catch (Exception e) {
log.error("执行脱敏操做时发生异常,脱敏异常时为了不影响主流程的正常运行,返回原始值");
}
}
}
return obj;
}
/**
* 数据脱敏
* @param value
* @return
*/
public static String desensitize(String value,String type) {
if(StringUtils.isBlank(value) || StringUtils.isBlank(type) || Objects.isNull(desensitizeMap.get(type))){
log.info("脱敏关键元素缺失,不做脱敏操做");
return value;
}
return desensitizeMap.get(type).apply(value);
}
}
package com.kang.mongodb.pojo;
import cn.hutool.core.util.DesensitizedUtil;
import com.kang.mongodb.annotation.Sensitive;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* @Author Emperor Kang
* @ClassName UserInfo
* @Description TODO
* @Date 2023/9/4 11:35
* @Version 1.0
* @Motto 让营地比你来时更干净
*/
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class UserInfo {
@Sensitive(type = DesensitizedUtil.DesensitizedType.CHINESE_NAME)
private String name;
@Sensitive(type = DesensitizedUtil.DesensitizedType.MOBILE_PHONE)
private String phone;
@Sensitive(type = DesensitizedUtil.DesensitizedType.ADDRESS)
private String address;
@Sensitive(type = DesensitizedUtil.DesensitizedType.EMAIL)
private String email;
}
package com.kang.mongodb;
import cn.hutool.core.util.DesensitizedUtil;
import com.kang.mongodb.pojo.UserInfo;
import com.kang.mongodb.utils.SensitiveUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
/**
* @Author Emperor Kang
* @ClassName SensitiveUtilTest
* @Description TODO
* @Date 2023/9/4 11:28
* @Version 1.0
* @Motto 让营地比你来时更干净
*/
@Slf4j
public class SensitiveUtilTest {
@Test
public void sensitiveTest(){
UserInfo userInfo = new UserInfo("王冬国", "1378569857", "河南上商丘市民权县葫芦乡葫芦村", "[email protected]");
UserInfo desensitize = SensitiveUtil.desensitize(userInfo);
log.info("脱敏后的数据:{}",desensitize);
String desensitize1 = SensitiveUtil.desensitize("1378569857", DesensitizedUtil.DesensitizedType.MOBILE_PHONE.name());
log.info("脱敏后的数据:{}",desensitize1);
}
}
结果
13:51:38.380 [main] INFO com.kang.mongodb.utils.SensitiveUtil - 当前字段:name,脱敏前的值:王冬国,脱敏后的值:王**
13:51:38.384 [main] INFO com.kang.mongodb.utils.SensitiveUtil - 当前字段:phone,脱敏前的值:1378569857,脱敏后的值:137***9857
13:51:38.384 [main] INFO com.kang.mongodb.utils.SensitiveUtil - 当前字段:address,脱敏前的值:河南上商丘市民权县葫芦乡葫芦村,脱敏后的值:河南上商丘市民********
13:51:38.384 [main] INFO com.kang.mongodb.utils.SensitiveUtil - 当前字段:email,脱敏前的值:[email protected],脱敏后的值:m****@163.com
13:51:38.384 [main] INFO com.kang.mongodb.SensitiveUtilTest - 脱敏后的数据:UserInfo(name=王**, phone=137***9857, address=河南上商丘市民********, email=m****@163.com)
13:51:38.390 [main] INFO com.kang.mongodb.SensitiveUtilTest - 脱敏后的数据:137***9857