版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/a1053765496/article/details/120483598
先上效果图:
开始
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 字段脱敏注解,隐藏部位,以*号显示
*
* @author lixx
* @version 1.0
* @since 2021-08-25 17:18
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveSerializer.class)
public @interface Sensitive {
/**
* 前缀长度,优先级L2
*/
int prefix() default 3;
/**
* 后缀长度,优先级L2
*/
int suffix() default 4;
/**
* 脱敏替换字符,优先级L1
*/
String maskChar() default "*";
/**
* 脱敏数据类型,优先级L1,L2优先级配置失效
*/
SensitiveEnum type() default SensitiveEnum.NONE;
}
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 脱敏类型枚举
*
* @author lixx
* @version 1.0
* @since 2021-08-25 17:19
*/
@Getter
@AllArgsConstructor
public enum SensitiveEnum {
/**
* 中文名,只显示最后一位
* 只有中文才生效
*/
CHINESE_NAME(0, 1),
/**
* 中文名2,只隐藏第一位
* 只有中文才生效
*/
CHINESE_NAME2(-1, 0),
/**
* 手机号码,显示开头3位,后4位,中间隐藏
*/
PHONE(3, 4),
/**
* 银行卡,显示开头2 ,结束2,中间隐藏
*/
BANK_CARD(2, 2),
/**
* 身份证号码,显示前面2位,和后面4位,其他隐藏
*/
ID_CARD(2, 4),
/**
* 电子邮箱,显示开头1位结尾1位,以及@后面的
*/
EMAIL(1, 1),
;
public final int prefixLength;
public final int suffixLength;
}
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 自定义脱敏数据序列化
*
* @author lixx
* @version 1.0
* @since 2021-08-25 18:01
*/
@NoArgsConstructor
@AllArgsConstructor
public class SensitiveSerializer extends JsonSerializer<Object> implements ContextualSerializer {
private int prefixLength;
private int suffixLength;
private String maskChar;
private SensitiveEnum sensitiveEnum;
public final static String template = "(?<=\\w{%s})\\w(?=\\w{%s})";
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (Objects.nonNull(value)) {
if (value instanceof String[]) {
String[] arr = (String[]) value;
gen.writeStartArray();
for (String s : arr) {
gen.writeString(s.trim().replaceAll(String.format(template, prefixLength, suffixLength), maskChar));
}
gen.writeEndArray();
}
if (value instanceof List) {
List<?> list = (List<?>) value;
if (!CollectionUtils.isEmpty(list) && list.get(0).getClass().equals(String.class)) {
gen.writeStartArray();
for (Object o : list) {
gen.writeString(((String) o).trim().replaceAll(String.format(template, prefixLength, suffixLength), maskChar));
}
gen.writeEndArray();
}
}
if (value instanceof String) {
String val = value.toString();
if (sensitiveEnum.equals(SensitiveEnum.CHINESE_NAME) || sensitiveEnum.equals(SensitiveEnum.CHINESE_NAME2)) {
if (checkCountName(val)) {
if (prefixLength == -1) {
gen.writeString(StringUtils.leftPad(StringUtils.right(val, val.length() - 1), val.length(), maskChar));
} else {
String left = StringUtils.left(val, prefixLength);
gen.writeString(StringUtils.rightPad(left, val.length() - suffixLength, maskChar).concat(StringUtils.right(val, suffixLength)));
}
} else {
gen.writeString(((String) value).trim().replaceAll(String.format(template, prefixLength, suffixLength), maskChar));
}
} else {
if (checkEmail(val)) {
gen.writeString(email(val, prefixLength, suffixLength, maskChar));
} else {
gen.writeString(((String) value).trim().replaceAll(String.format(template, prefixLength, suffixLength), maskChar));
}
}
}
}
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
if (Objects.nonNull(property)) {
Sensitive mask = property.getAnnotation(Sensitive.class);
if (Objects.isNull(mask)) {
mask = property.getContextAnnotation(Sensitive.class);
}
//可以改造成初始化regex正则表达式
if (mask.type().equals(SensitiveEnum.NONE)) {
return new SensitiveSerializer(mask.prefix(), mask.suffix(), mask.maskChar(), mask.type());
} else {
return new SensitiveSerializer(mask.type().prefixLength, mask.type().suffixLength, mask.maskChar(), mask.type());
}
} else {
return prov.findNullValueSerializer(null);
}
}
@Override
public Class<Object> handledType() {
return Object.class;
}
/**
* 判断是否是汉字
*/
private boolean checkCountName(String countName) {
Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
Matcher m = p.matcher(countName);
return m.find();
}
/**
* 判断是否是邮箱格式
*/
private boolean checkEmail(String email) {
Pattern patten = Pattern.compile("[\\w]+@([\\w]+.)+[\\w]+");
Matcher matcher = patten.matcher(email);
return matcher.matches();
}
public static String email(String email, int prefixLength, int suffixLength, String maskChar) {
if (StringUtils.isBlank(email)) {
return "";
}
int index = StringUtils.indexOf(email, "@");
if (index <= prefixLength + suffixLength) {
return email;
} else {
String emailPrefix = email.substring(0, index);
String emailSuffix = email.substring(index);
return emailPrefix.replaceAll(String.format(template, prefixLength, suffixLength), maskChar).concat(emailSuffix);
}
}
}
使用如下:
/**
* @author lixx
* @version 1.0
* @since 2021-07-22 19:26
*/
@Data
public class SysUser {
/**
* 手机号码,需要脱敏的属性字段
*/
@Sensitive(type = SensitiveEnum.PHONE)
private String mobile;
}
效果如下:
结语:
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/72541.html