feat: 支持 vo 返回的脱敏
parent
e637bff8cd
commit
5c8e41b847
@ -0,0 +1,21 @@
|
||||
package cn.iocoder.yudao.framework.desensitize.annotation.constraints;
|
||||
|
||||
import cn.iocoder.yudao.framework.desensitize.annotation.SliderDesensitize;
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 中文名
|
||||
*/
|
||||
@Documented
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@JacksonAnnotationsInside
|
||||
@SliderDesensitize(prefixKeep = 1, suffixKeep = 0, replacer = "*") // 中文名;比如:刘子豪脱敏之后为刘**
|
||||
public @interface ChineseNameDesensitize {
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
package cn.iocoder.yudao.framework.desensitize.constants;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class DesensitizeConstants {
|
||||
|
||||
/**
|
||||
* 默认正则
|
||||
*/
|
||||
public static final String DEFAULT_REGEX = null;
|
||||
|
||||
/**
|
||||
* 默认保持长度
|
||||
*/
|
||||
public static final int DEFAULT_KEEP_LENGTH = -1;
|
||||
|
||||
/**
|
||||
* 默认替换字符
|
||||
*/
|
||||
public static final String DEFAULT_REPLACER = "****";
|
||||
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
package cn.iocoder.yudao.framework.desensitize.handler;
|
||||
|
||||
public class DefaultDesensitizationHandler implements DesensitizationHandler {
|
||||
|
||||
@Override
|
||||
public String handle(String origin) {
|
||||
return origin;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package cn.iocoder.yudao.framework.desensitize.handler;
|
||||
|
||||
public class RegexDesensitizationHandler implements DesensitizationHandler {
|
||||
|
||||
@Override
|
||||
public String desensitize(String origin, Object... arg) {
|
||||
String regex = (String) arg[0];
|
||||
String replacer = (String) arg[1];
|
||||
|
||||
return origin.replaceAll(regex, replacer);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package cn.iocoder.yudao.framework.desensitize.handler;
|
||||
|
||||
public class SliderDesensitizationHandler implements DesensitizationHandler {
|
||||
|
||||
@Override
|
||||
public String desensitize(String origin, Object... arg) {
|
||||
int prefixKeep = (Integer) arg[0];
|
||||
int suffixKeep = (Integer) arg[1];
|
||||
String replacer = (String) arg[2];
|
||||
|
||||
int length = origin.length();
|
||||
|
||||
// 原始字符串长度小于等于保留长度,则原始字符串全部替换
|
||||
if (prefixKeep >= length || suffixKeep >= length) {
|
||||
return buildReplacerByLength(replacer, length);
|
||||
}
|
||||
|
||||
// 如果原始字符串小于等于前后缀保留字符串长度,则原始字符串全部替换
|
||||
if ((prefixKeep + suffixKeep) >= length) {
|
||||
return buildReplacerByLength(replacer, length);
|
||||
}
|
||||
|
||||
int interval = length - prefixKeep - suffixKeep;
|
||||
return origin.substring(0, prefixKeep) +
|
||||
buildReplacerByLength(replacer, interval) +
|
||||
origin.substring(prefixKeep + interval);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据长度循环构建替换符
|
||||
*
|
||||
* @param replacer 替换符
|
||||
* @param length 长度
|
||||
* @return 构建后的替换符
|
||||
*/
|
||||
private String buildReplacerByLength(String replacer, int length) {
|
||||
return String.valueOf(replacer).repeat(Math.max(0, length));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
package cn.iocoder.yudao.framework.desensitize.serializer;
|
||||
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.desensitize.annotation.Desensitize;
|
||||
import cn.iocoder.yudao.framework.desensitize.annotation.RegexDesensitize;
|
||||
import cn.iocoder.yudao.framework.desensitize.annotation.SliderDesensitize;
|
||||
import cn.iocoder.yudao.framework.desensitize.handler.DesensitizationHandler;
|
||||
import cn.iocoder.yudao.framework.desensitize.handler.DesensitizationHandlerHolder;
|
||||
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 com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* 脱敏序列化器
|
||||
*/
|
||||
public class StringDesensitizeSerializer extends StdSerializer<String> implements ContextualSerializer {
|
||||
private final DesensitizationHandler desensitizationHandler;
|
||||
|
||||
protected StringDesensitizeSerializer(DesensitizationHandler desensitizationHandler) {
|
||||
super(String.class);
|
||||
this.desensitizationHandler = desensitizationHandler;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
|
||||
Desensitize annotation = beanProperty.getAnnotation(Desensitize.class);
|
||||
if (annotation == null) {
|
||||
return this;
|
||||
}
|
||||
|
||||
return new StringDesensitizeSerializer(DesensitizationHandlerHolder.getDesensitizationHandler(annotation.desensitizationHandler()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(String value, JsonGenerator gen, SerializerProvider serializerProvider) throws IOException {
|
||||
if (StrUtil.isBlank(value)) {
|
||||
gen.writeNull();
|
||||
return;
|
||||
}
|
||||
|
||||
String currentName = gen.getOutputContext().getCurrentName();
|
||||
Object currentValue = gen.getCurrentValue();
|
||||
Class<?> currentValueClass = currentValue.getClass();
|
||||
Field field = ReflectUtil.getField(currentValueClass, currentName);
|
||||
|
||||
// 滑动处理器
|
||||
SliderDesensitize sliderDesensitize = field.getAnnotation(SliderDesensitize.class);
|
||||
if (sliderDesensitize != null) {
|
||||
value = this.desensitizationHandler.desensitize(value, sliderDesensitize.prefixKeep(), sliderDesensitize.suffixKeep(), sliderDesensitize.replacer());
|
||||
}
|
||||
|
||||
// 正则处理器
|
||||
RegexDesensitize regexDesensitize = field.getAnnotation(RegexDesensitize.class);
|
||||
if (regexDesensitize != null) {
|
||||
value = this.desensitizationHandler.desensitize(value, regexDesensitize.regex(), regexDesensitize.replacer());
|
||||
}
|
||||
|
||||
// 自定义处理器
|
||||
Desensitize desensitize = field.getAnnotation(Desensitize.class);
|
||||
if (desensitize != null) {
|
||||
value = this.desensitizationHandler.desensitize(value);
|
||||
}
|
||||
|
||||
gen.writeString(value);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package cn.iocoder.yudao.framework.desensitize.handler;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class DesensitizationHandlerTest {
|
||||
|
||||
@Test
|
||||
public void testSliderDesensitizationHandler() {
|
||||
DesensitizationHandler handler = DesensitizationHandlerHolder.getDesensitizationHandler(SliderDesensitizationHandler.class);
|
||||
|
||||
Assertions.assertEquals("A****FG", handler.desensitize("ABCDEFG", 1, 2, "*"));
|
||||
Assertions.assertEquals("芋**码", handler.desensitize("芋道源码", 1, 1, "*"));
|
||||
Assertions.assertEquals("****", handler.desensitize("芋道源码", 4, 0, "*"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegexDesensitizationHandler() {
|
||||
DesensitizationHandler handler = DesensitizationHandlerHolder.getDesensitizationHandler(RegexDesensitizationHandler.class);
|
||||
|
||||
Assertions.assertEquals("e****@gmail.com", handler.desensitize("example@gmail.com", "(^.)[^@]*(@.*$)", "$1****$2"));
|
||||
Assertions.assertEquals("***,铁***", handler.desensitize("他妈的,铁废物", "他妈的|去你大爷|卧槽|草泥马|废物", "***"));
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue