問(wèn)題
在電商業(yè)務(wù)中彪置,對(duì)于一些敏感數(shù)據(jù)(比如 用戶姓名,用戶身份證蝇恶,用戶手機(jī)號(hào)碼拳魁,用戶銀行卡等),需要進(jìn)行脫敏操作撮弧,為了業(yè)務(wù)開發(fā)的方便潘懊,應(yīng)該要提供對(duì)應(yīng)的處理方法, 能夠使得業(yè)務(wù)開發(fā)能夠自由的配置贿衍。
方案
所以采取了和之前文章中授舟,我們采取的方案是,重新修改默認(rèn)的ObjectMapper
對(duì)象贸辈,添加一個(gè)自定義類型的DesensitizationBeanSerializerModifier
释树,通過(guò)對(duì)于所有的String
字符串都進(jìn)行過(guò)濾,并且提供了 對(duì)應(yīng)的注解 Desensitization
擎淤,和一些參數(shù)奢啥, 可以根據(jù)不同的脫敏規(guī)則進(jìn)行自由的配置
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
@Documented
public @interface Desensitization {
//前后分別展示多少個(gè)字符
int showPrefixLength() default 3;
int showSuffixLength() default 4;
//針對(duì)長(zhǎng)度進(jìn)行多種處理,0為不考慮長(zhǎng)度
int strLength() default 0;
}
下面為自己定義的序列化方法
public static class DesensitizationBeanSerializerModifier extends BeanSerializerModifier {
@Override
public List<BeanPropertyWriter> changeProperties(SerializationConfig config,
BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
for (Object beanProperty : beanProperties) {
BeanPropertyWriter writer = (BeanPropertyWriter) beanProperty;
if (isStringType(writer)) {
Desensitization desensitization = ((BeanPropertyWriter) beanProperty).getAnnotation(Desensitization.class);
Desensitizations desensitizations = ((BeanPropertyWriter) beanProperty).getAnnotation(Desensitizations.class);
if (desensitization != null || desensitizations != null) {
StringDesensitizationJsonSerializer stringDesensitizationJsonSerializer = new StringDesensitizationJsonSerializer();
if (desensitization != null) {
stringDesensitizationJsonSerializer.setDesensitization(desensitization);
}
if (desensitizations != null) {
stringDesensitizationJsonSerializer.setDesensitizations(desensitizations);
}
writer.assignSerializer(stringDesensitizationJsonSerializer);
}
}
}
return beanProperties;
}
/**
* 是否是string
*/
private boolean isStringType(BeanPropertyWriter writer) {
Class<?> clazz = writer.getType().getRawClass();
return CharSequence.class.isAssignableFrom(clazz) || Character.class.isAssignableFrom(clazz);
}
}
具體的針對(duì)脫敏注解的邏輯操作
/**
* 處理字符串脫敏處理
*/
@NoArgsConstructor
@AllArgsConstructor
public static class StringDesensitizationJsonSerializer extends JsonSerializer<Object> {
@Setter
private Desensitization desensitization;
@Setter
private Desensitizations desensitizations;
@Override
public void serialize(Object o, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider) throws IOException {
if (desensitization == null && desensitizations == null) {
return;
}
Desensitization[] desensitizationArray = getDesensitizationArray();
String value = o.toString();
int valueLength = value.length();
boolean matchSize = false;
int zeroLength = -1;
int index = 0;
for (Desensitization desensitization : desensitizationArray) {
if (valueLength == desensitization.strLength()) {
matchSize = true;
jsonGenerator
.writeString(fixedVal(value, desensitization.showPrefixLength(), desensitization.showSuffixLength()));
} else if (desensitization.strLength() == 0 && zeroLength == -1) {
zeroLength = index++;
} else {
index++;
}
}
if (!matchSize) {
if(zeroLength != -1) {
jsonGenerator
.writeString(fixedVal(value, desensitizationArray[zeroLength].showPrefixLength(),
desensitizationArray[zeroLength].showSuffixLength()));
} else {
jsonGenerator
.writeString(fixedVal(value, desensitizationArray[0].showPrefixLength(),
desensitizationArray[0].showSuffixLength()));
}
}
}
private Desensitization[] getDesensitizationArray() {
int size = 0;
if (desensitization != null) {
size++;
}
if (desensitizations != null) {
size += desensitizations.value().length;
}
Desensitization[] desensitizationArray = new Desensitization[size];
int index = 0;
if (desensitization != null) {
desensitizationArray[index++] = desensitization;
}
if (desensitizations != null) {
System.arraycopy(desensitizations.value(), 0, desensitizationArray, index, size - index);
}
return desensitizationArray;
}
private String fixedVal(String value, int prefixLength, int suffixLength) {
if (StringUtils.isBlank(value)) {
return Strings.repeat("*", value.length());
}
if(value.length() <= prefixLength + suffixLength) {
return value;
}
int length = value.length();
String prefix = value.substring(0, prefixLength);
String suffix = value.substring(length - suffixLength);
String stars = Strings.repeat("*", length - (prefixLength + suffixLength));
return prefix + stars + suffix;
}
}
這樣對(duì)于一個(gè)Bean
里面的對(duì)象嘴拢,都可以進(jìn)行相關(guān)操作扫尺。
下面給一個(gè)例子
@Data
public class DesensitizationsBean {
@Desensitizations(value = {
@Desensitization(strLength = 4, showPrefixLength = 2, showSuffixLength = 1),
@Desensitization(strLength = 1, showPrefixLength = 1, showSuffixLength = 1),
@Desensitization(strLength = 2, showPrefixLength = 1, showSuffixLength = 0),
@Desensitization(strLength = 3, showPrefixLength = 0, showSuffixLength = 1),
})
private String mobileA;
@Desensitizations(value = {
@Desensitization,
@Desensitization(strLength = 1, showPrefixLength = 0, showSuffixLength = 1),
@Desensitization(strLength = 2, showPrefixLength = 1, showSuffixLength = 0),
@Desensitization(strLength = 3, showPrefixLength = 0, showSuffixLength = 1),
@Desensitization(strLength = 4, showPrefixLength = 1, showSuffixLength = 1),
})
private String mobileB;
@Desensitizations(value = {
@Desensitization,
@Desensitization(strLength = 1, showPrefixLength = 1, showSuffixLength = 1),
@Desensitization(strLength = 2, showPrefixLength = 1, showSuffixLength = 0),
@Desensitization(strLength = 3, showPrefixLength = 0, showSuffixLength = 1),
@Desensitization(strLength = 4, showPrefixLength = 1, showSuffixLength = 1),
})
private String mobileC;
@Desensitizations(value = {
@Desensitization,
@Desensitization(strLength = 1, showPrefixLength = 1, showSuffixLength = 1),
@Desensitization(strLength = 2, showPrefixLength = 1, showSuffixLength = 0),
@Desensitization(strLength = 3, showPrefixLength = 0, showSuffixLength = 1),
@Desensitization(strLength = 4, showPrefixLength = 1, showSuffixLength = 1),
})
private String mobileD;
@Desensitizations(value = {
@Desensitization,
@Desensitization(strLength = 1, showPrefixLength = 1, showSuffixLength = 1),
@Desensitization(strLength = 2, showPrefixLength = 1, showSuffixLength = 0),
@Desensitization(strLength = 3, showPrefixLength = 0, showSuffixLength = 1),
@Desensitization(strLength = 4, showPrefixLength = 1, showSuffixLength = 1),
})
private String mobileE;
@Desensitizations(value = {
@Desensitization,
@Desensitization(strLength = 1, showPrefixLength = 1, showSuffixLength = 1),
@Desensitization(strLength = 2, showPrefixLength = 1, showSuffixLength = 0),
@Desensitization(strLength = 3, showPrefixLength = 0, showSuffixLength = 1),
@Desensitization(strLength = 4, showPrefixLength = 1, showSuffixLength = 1),
})
private String mobileF;
private List<DesensitizationsSubBean> subBeanList;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class DesensitizationsSubBean {
@Desensitizations(value = {
@Desensitization,
@Desensitization(strLength = 1, showPrefixLength = 1, showSuffixLength = 1),
@Desensitization(strLength = 2, showPrefixLength = 1, showSuffixLength = 0),
@Desensitization(strLength = 3, showPrefixLength = 0, showSuffixLength = 1),
@Desensitization(strLength = 4, showPrefixLength = 1, showSuffixLength = 1),
})
private Long mobile1;
@Desensitizations(value = {
@Desensitization,
@Desensitization(strLength = 1, showPrefixLength = 1, showSuffixLength = 1),
@Desensitization(strLength = 2, showPrefixLength = 1, showSuffixLength = 0),
@Desensitization(strLength = 3, showPrefixLength = 0, showSuffixLength = 1),
@Desensitization(strLength = 4, showPrefixLength = 1, showSuffixLength = 1),
})
private String mobile2;
@Desensitizations(value = {
@Desensitization,
@Desensitization(strLength = 1, showPrefixLength = 1, showSuffixLength = 1),
@Desensitization(strLength = 2, showPrefixLength = 1, showSuffixLength = 0),
@Desensitization(strLength = 3, showPrefixLength = 0, showSuffixLength = 1),
@Desensitization(strLength = 4, showPrefixLength = 1, showSuffixLength = 1),
})
private String mobile3;
@Desensitizations(value = {
@Desensitization,
@Desensitization(strLength = 1, showPrefixLength = 1, showSuffixLength = 1),
@Desensitization(strLength = 2, showPrefixLength = 1, showSuffixLength = 0),
@Desensitization(strLength = 3, showPrefixLength = 0, showSuffixLength = 1),
@Desensitization(strLength = 4, showPrefixLength = 1, showSuffixLength = 1),
})
private String mobile4;
@Desensitizations(value = {
@Desensitization,
@Desensitization(strLength = 1, showPrefixLength = 1, showSuffixLength = 1),
@Desensitization(strLength = 2, showPrefixLength = 1, showSuffixLength = 0),
@Desensitization(strLength = 3, showPrefixLength = 0, showSuffixLength = 1),
@Desensitization(strLength = 4, showPrefixLength = 1, showSuffixLength = 1),
})
private String mobile5;
@Desensitizations(value = {
@Desensitization,
@Desensitization(strLength = 1, showPrefixLength = 1, showSuffixLength = 1),
@Desensitization(strLength = 2, showPrefixLength = 1, showSuffixLength = 0),
@Desensitization(strLength = 3, showPrefixLength = 0, showSuffixLength = 1),
@Desensitization(strLength = 4, showPrefixLength = 1, showSuffixLength = 1),
})
private String mobile6;
}
}
@GetMapping("/desensitizations")
public BaseResult desensitizations() {
DesensitizationsBean desensitizationsBean = new DesensitizationsBean();
desensitizationsBean.setMobileA("18507313226");
desensitizationsBean.setMobileB("龍");
desensitizationsBean.setMobileC("龍哲");
desensitizationsBean.setMobileD("龍若妍");
desensitizationsBean.setMobileE("龍若妍好");
desensitizationsBean.setMobileF("18507313226");
desensitizationsBean.setSubBeanList(
Lists.newArrayList(
DesensitizationsSubBean.builder().mobile1(18507313226L).mobile2("龍").mobile3("龍哲").mobile4("龍若妍").mobile5("龍若妍好").mobile6("18507313226").build(),
DesensitizationsSubBean.builder().mobile1(18507313226L).mobile2("龍").mobile3("龍哲").mobile4("龍若妍").mobile5("龍若妍好").mobile6("18507313226").build(),
DesensitizationsSubBean.builder().mobile1(18507313226L).mobile2("龍").mobile3("龍哲").mobile4("龍若妍").mobile5("龍若妍好").mobile6("18507313226").build()
));
return BaseResult.success(desensitizationsBean);
}
執(zhí)行的結(jié)果是
{
"code": 0,
"msg": "success",
"traceId": "6ba0c884b10fbd8f",
"data": {
"mobileA": "18********6",
"mobileB": "龍",
"mobileC": "龍*",
"mobileD": "**妍",
"mobileE": "龍**好",
"mobileF": "185****3226",
"subBeanList": [
{
"mobile1": 18507313226,
"mobile2": "龍",
"mobile3": "龍*",
"mobile4": "**妍",
"mobile5": "龍**好",
"mobile6": "185****3226"
},
{
"mobile1": 18507313226,
"mobile2": "龍",
"mobile3": "龍*",
"mobile4": "**妍",
"mobile5": "龍**好",
"mobile6": "185****3226"
},
{
"mobile1": 18507313226,
"mobile2": "龍",
"mobile3": "龍*",
"mobile4": "**妍",
"mobile5": "龍**好",
"mobile6": "185****3226"
}
]
}
}
這樣業(yè)務(wù)放就只要簡(jiǎn)單的在想要脫敏的字段上加入對(duì)應(yīng)的注解和配置對(duì)應(yīng)的參數(shù)就可以了。
結(jié)束
轉(zhuǎn)載請(qǐng)注明作者和出處炊汤,并添加本頁(yè)鏈接正驻。
原文鏈接: //tech.cnhnb.com/post/6