一、简介
系统使用
Jackson
序列化策略,对标注了Sensitive
注解的属性进行脱敏处理
基于Hutool 脱敏案列:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside// 表示只对有此注解的字段进行序列化
@JsonSerialize(using = SensitiveJsonSerializer.class)// 指定序列化器
public @interface Sensitive {
SensitiveStrategy strategy();
}
我们以身份证号码为例:
// 5***************1X
DesensitizedUtil.idCardNum("51343620000320711X", 1, 2);
对于约定俗成的脱敏,我们可以不用指定隐藏位数,比如手机号:
// 180****1999
DesensitizedUtil.mobilePhone("18049531999");
当然还有一些简单粗暴的脱敏,比如密码,只保留了位数信息:
// **********
DesensitizedUtil.password("1234567890");
二、若依框架脱敏流程
2.1 注解类
@JacksonAnnotationsInside// 表示只对有此注解的字段进行序列化
@JsonSerialize(using = SensitiveJsonSerializer.class)// 指定序列化器
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside// 表示只对有此注解的字段进行序列化
@JsonSerialize(using = SensitiveJsonSerializer.class)// 指定序列化器
public @interface Sensitive {
SensitiveStrategy strategy();
}
2.2 脱了策略枚举类
@AllArgsConstructor
public enum SensitiveStrategy {
/**
* 身份证脱敏
*/
ID_CARD(s -> DesensitizedUtil.idCardNum(s, 3, 4)),
/**
* 手机号脱敏
*/ PHONE(DesensitizedUtil::mobilePhone),
/**
* 地址脱敏
*/
ADDRESS(s -> DesensitizedUtil.address(s, 8)),
/**
* 邮箱脱敏
*/
EMAIL(DesensitizedUtil::email),
/**
* 银行卡
*/
BANK_CARD(DesensitizedUtil::bankCard);
//可自行添加其他脱敏策略
private final Function<String, String> desensitizer;
public Function<String, String> desensitizer() {
return desensitizer;
}
}
使用的是HuTool包中的 DesensitizedUtil 类进行脱敏
/** * 脱敏,使用默认的脱敏策略 * <pre> * DesensitizedUtil.desensitized("100", DesensitizedUtil.DesensitizedType.USER_ID)) = "0" * DesensitizedUtil.desensitized("段正淳", DesensitizedUtil.DesensitizedType.CHINESE_NAME)) = "段**" * DesensitizedUtil.desensitized("51343620000320711X", DesensitizedUtil.DesensitizedType.ID_CARD)) = "5***************1X" * DesensitizedUtil.desensitized("09157518479", DesensitizedUtil.DesensitizedType.FIXED_PHONE)) = "0915*****79" * DesensitizedUtil.desensitized("18049531999", DesensitizedUtil.DesensitizedType.MOBILE_PHONE)) = "180****1999" * DesensitizedUtil.desensitized("北京市海淀区马连洼街道289号", DesensitizedUtil.DesensitizedType.ADDRESS)) = "北京市海淀区马********" * DesensitizedUtil.desensitized("duandazhi-jack@gmail.com.cn", DesensitizedUtil.DesensitizedType.EMAIL)) = "d*************@gmail.com.cn" * DesensitizedUtil.desensitized("1234567890", DesensitizedUtil.DesensitizedType.PASSWORD)) = "**********" * DesensitizedUtil.desensitized("苏D40000", DesensitizedUtil.DesensitizedType.CAR_LICENSE)) = "苏D4***0" * DesensitizedUtil.desensitized("11011111222233333256", DesensitizedUtil.DesensitizedType.BANK_CARD)) = "1101 **** **** **** 3256" * DesensitizedUtil.desensitized("192.168.1.1", DesensitizedUtil.DesensitizedType.IPV4)) = "192.*.*.*" * </pre> * * @param str 字符串 * @param desensitizedType 脱敏类型;可以脱敏:用户id、中文名、身份证号、座机号、手机号、地址、电子邮件、密码 * @return 脱敏之后的字符串 * @author dazer and neusoft and qiaomu * @since 5.6.2 */
2.3 数据脱敏的序列化工具
- 重写序列化接口,调用具体序列化策略
- 重写创建上写文方法,指定当前处理的策略
@Slf4j
public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer {
private SensitiveStrategy strategy;
/**
* <简述> 重写序列化方法
* <详细描述>
* @author syf
* @date 2024/9/14 17:01
* @param value
* @param gen
* @param serializers
*/
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
try {
// 获取注解
SensitiveService sensitiveService = SpringUtils.getBean(SensitiveService.class);
// 判断是否开启脱敏
if (ObjectUtil.isNotNull(sensitiveService) && sensitiveService.isSensitive()) {
// 调用策略 strategy.desensitizer().apply(value), gen.writeString写入值
gen.writeString(strategy.desensitizer().apply(value));
} else {
gen.writeString(value);
}
} catch (BeansException e) {
log.error("脱敏实现不存在, 采用默认处理 => {}", e.getMessage());
gen.writeString(value);
}
}
/**
* <简述>重写创建上下文方法
* <详细描述>
* @author syf
* @date 2024/9/14 16:54
* @param prov
* @param property
* @return com.fasterxml.jackson.databind.JsonSerializer<?>
*/
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
// 获取注解
Sensitive annotation = property.getAnnotation(Sensitive.class);
//注解不为空 并且 类型为String
if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) {
// 设置当前注解的策略为注解里面策略
this.strategy = annotation.strategy();
return this;
}
// 返回默认序列化器
return prov.findValueSerializer(property.getType(), property);
}
}
注意: 默认管理员不过滤 需自行根据业务重写实现
public interface SensitiveService {
/**
* 是否脱敏
*/
boolean isSensitive();
}
三、测试案例
@RestController
@RequestMapping("/demo/sensitive")
public class TestSensitiveController extends BaseController {
/**
* 测试数据脱敏
*/
@GetMapping("/test")
public R<TestSensitive> test() {
TestSensitive testSensitive = new TestSensitive();
testSensitive.setIdCard("210397198608215431");
testSensitive.setPhone("17640125371");
testSensitive.setAddress("北京市朝阳区某某四合院1203室");
testSensitive.setEmail("17640125371@163.com");
testSensitive.setBankCard("6226456952351452853");
return R.ok(testSensitive);
}
@Data
static class TestSensitive {
/**
* 身份证
*/
@Sensitive(strategy = SensitiveStrategy.ID_CARD)
private String idCard;
/**
* 电话
*/
@Sensitive(strategy = SensitiveStrategy.PHONE)
private String phone;
/**
* 地址
*/
@Sensitive(strategy = SensitiveStrategy.ADDRESS)
private String address;
/**
* 邮箱
*/
@Sensitive(strategy = SensitiveStrategy.EMAIL)
private String email;
/**
* 银行卡
*/
@Sensitive(strategy = SensitiveStrategy.BANK_CARD)
private String bankCard;
}
}
博主精心整理专栏,CV大法即可用,感谢您小手点一点 手动跪拜:
1- SpringBoot框架常用配置(若依),代码解读:
http://t.csdnimg.cn/jpsSN
2- java常用工具类整理,示例演示:
http://t.csdnimg.cn/gmCfJ
3- CompletableFuture 异步编排与实际代码展示
http://t.csdnimg.cn/ZuC0N
4- XXL-JOB 详细学习,手把手带入门
http://t.csdnimg.cn/lyR7Y