修改脱敏策略
This commit is contained in:
@@ -5,7 +5,7 @@ import java.lang.annotation.*;
|
|||||||
/**
|
/**
|
||||||
* 脱敏配置元注解
|
* 脱敏配置元注解
|
||||||
* <p>
|
* <p>
|
||||||
* 标注在字段上则标记脱敏配置
|
* 标注在字段上则标记该字段执行 http 序列化时脱敏
|
||||||
*
|
*
|
||||||
* @author Jiahang Li
|
* @author Jiahang Li
|
||||||
* @version 1.0.0
|
* @version 1.0.0
|
||||||
@@ -19,12 +19,12 @@ public @interface Desensitize {
|
|||||||
/**
|
/**
|
||||||
* @return 起始保留字符数
|
* @return 起始保留字符数
|
||||||
*/
|
*/
|
||||||
int keepStart() default 0;
|
int keepStart() default 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return 结束保留字符数
|
* @return 结束保留字符数
|
||||||
*/
|
*/
|
||||||
int keepEnd() default 0;
|
int keepEnd() default 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return 脱敏字符
|
* @return 脱敏字符
|
||||||
|
|||||||
@@ -5,16 +5,15 @@ import java.lang.annotation.*;
|
|||||||
/**
|
/**
|
||||||
* 脱敏配置元注解
|
* 脱敏配置元注解
|
||||||
* <p>
|
* <p>
|
||||||
* 标注在方法上则标记过滤开启
|
* 标注在类上则标记该类执行序列化时会执行脱敏
|
||||||
* 多层对象脱敏需要在字段上标注
|
|
||||||
*
|
*
|
||||||
* @author Jiahang Li
|
* @author Jiahang Li
|
||||||
* @version 1.0.0
|
* @version 1.0.0
|
||||||
* @since 2023/6/29 16:58
|
* @since 2023/6/29 16:58
|
||||||
*/
|
*/
|
||||||
@Target({ElementType.METHOD, ElementType.FIELD})
|
@Target({ElementType.TYPE})
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Documented
|
@Documented
|
||||||
public @interface DoDesensitize {
|
public @interface DesensitizeObject {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -9,8 +9,6 @@ package com.orion.ops.framework.common.constant;
|
|||||||
*/
|
*/
|
||||||
public interface ResponseAdviceOrderConst {
|
public interface ResponseAdviceOrderConst {
|
||||||
|
|
||||||
int DESENSITIZE = Integer.MIN_VALUE + 2000;
|
int WRAPPER = Integer.MIN_VALUE + 1000;
|
||||||
|
|
||||||
int WRAPPER = Integer.MIN_VALUE + 3000;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,51 @@
|
|||||||
package com.orion.ops.framework.desensitize.config;
|
package com.orion.ops.framework.desensitize.config;
|
||||||
|
|
||||||
import com.orion.ops.framework.desensitize.core.handler.DesensitizeResultHandler;
|
import com.alibaba.fastjson.serializer.SerializeFilter;
|
||||||
|
import com.alibaba.fastjson.support.config.FastJsonConfig;
|
||||||
|
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
|
||||||
|
import com.orion.lang.utils.Arrays1;
|
||||||
|
import com.orion.ops.framework.desensitize.core.filter.DesensitizeValueSerializeFilter;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据脱敏置类
|
* 数据脱敏置类
|
||||||
|
* <p>
|
||||||
|
* 前置需要装配 orion-ops-spring-boot-starter-web
|
||||||
*
|
*
|
||||||
* @author Jiahang Li
|
* @author Jiahang Li
|
||||||
* @version 1.0.0
|
* @version 1.0.0
|
||||||
* @since 2023/6/29 16:55
|
* @since 2023/6/29 16:55
|
||||||
*/
|
*/
|
||||||
@AutoConfiguration
|
@AutoConfiguration
|
||||||
|
@AutoConfigureAfter(name = "com.orion.ops.framework.web.config.OrionWebAutoConfiguration")
|
||||||
public class OrionDesensitizeAutoConfiguration {
|
public class OrionDesensitizeAutoConfiguration {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return 返回结果脱敏处理器
|
* @return 返回 序列化脱敏过滤器
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public DesensitizeResultHandler desensitizeResultHandler() {
|
@ConditionalOnBean(FastJsonHttpMessageConverter.class)
|
||||||
return new DesensitizeResultHandler();
|
public DesensitizeValueSerializeFilter desensitizeResultHandler(FastJsonHttpMessageConverter converter) {
|
||||||
|
DesensitizeValueSerializeFilter desensitizeFilter = new DesensitizeValueSerializeFilter();
|
||||||
|
// 获取 json 配置
|
||||||
|
FastJsonConfig config = converter.getFastJsonConfig();
|
||||||
|
SerializeFilter[] filters = config.getSerializeFilters();
|
||||||
|
int filterLength = Arrays1.length(filters);
|
||||||
|
if (filterLength == 0) {
|
||||||
|
// 未设置配置
|
||||||
|
filters = new SerializeFilter[]{desensitizeFilter};
|
||||||
|
} else {
|
||||||
|
SerializeFilter[] newFilters = new SerializeFilter[filterLength + 1];
|
||||||
|
System.arraycopy(filters, 0, newFilters, 0, filterLength);
|
||||||
|
newFilters[filterLength] = desensitizeFilter;
|
||||||
|
filters = newFilters;
|
||||||
|
}
|
||||||
|
// 更新到配置
|
||||||
|
config.setSerializeFilters(filters);
|
||||||
|
return desensitizeFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package com.orion.ops.framework.desensitize.core.filter;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
import com.alibaba.fastjson.serializer.ValueFilter;
|
||||||
|
import com.orion.lang.utils.Objects1;
|
||||||
|
import com.orion.lang.utils.Strings;
|
||||||
|
import com.orion.lang.utils.collect.Maps;
|
||||||
|
import com.orion.lang.utils.reflect.Annotations;
|
||||||
|
import com.orion.lang.utils.reflect.Fields;
|
||||||
|
import com.orion.ops.framework.common.annotation.Desensitize;
|
||||||
|
import com.orion.ops.framework.common.annotation.DesensitizeObject;
|
||||||
|
import com.orion.ops.framework.common.utils.Desensitizes;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 脱敏序列化器
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2023/6/30 12:19
|
||||||
|
*/
|
||||||
|
public class DesensitizeValueSerializeFilter implements ValueFilter {
|
||||||
|
|
||||||
|
private static final Map<String, Map<String, Desensitize>> DESENSITIZE_FIELDS = new HashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object process(Object object, String name, Object value) {
|
||||||
|
if (object == null || value == null) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
Desensitize config = doDesensitizeField(object, name);
|
||||||
|
// 无需脱敏
|
||||||
|
if (config == null) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
// 脱敏
|
||||||
|
return Desensitizes.mix(Objects1.toString(value), config.keepStart(), config.keepEnd(), config.replacer());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否要执行脱敏
|
||||||
|
*
|
||||||
|
* @param object object
|
||||||
|
* @param name name
|
||||||
|
* @return 是否执行
|
||||||
|
*/
|
||||||
|
private Desensitize doDesensitizeField(Object object, String name) {
|
||||||
|
// 查询缓存
|
||||||
|
String className = object.getClass().toString();
|
||||||
|
Map<String, Desensitize> fields = DESENSITIZE_FIELDS.get(className);
|
||||||
|
if (fields == null) {
|
||||||
|
// 查询脱敏配置
|
||||||
|
fields = this.initClassDesensitize(object);
|
||||||
|
DESENSITIZE_FIELDS.put(className, fields);
|
||||||
|
}
|
||||||
|
// 无需脱敏
|
||||||
|
if (fields.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return fields.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化脱敏配置
|
||||||
|
*
|
||||||
|
* @param object object
|
||||||
|
* @return config
|
||||||
|
*/
|
||||||
|
private Map<String, Desensitize> initClassDesensitize(Object object) {
|
||||||
|
Class<?> dataClass = object.getClass();
|
||||||
|
// 检查是否为脱敏对象
|
||||||
|
DesensitizeObject has = Annotations.getAnnotation(dataClass, DesensitizeObject.class);
|
||||||
|
if (has == null) {
|
||||||
|
return Maps.empty();
|
||||||
|
}
|
||||||
|
Map<String, Desensitize> config = new HashMap<>();
|
||||||
|
// 获取对象字段
|
||||||
|
List<Field> fields = Fields.getFields(dataClass);
|
||||||
|
// 查询脱敏配置
|
||||||
|
for (Field field : fields) {
|
||||||
|
// 脱敏注解
|
||||||
|
Desensitize desensitize = Annotations.getAnnotation(field, Desensitize.class);
|
||||||
|
if (desensitize == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// json 注解
|
||||||
|
JSONField jsonField = Annotations.getAnnotation(field, JSONField.class);
|
||||||
|
String fieldName = field.getName();
|
||||||
|
String jsonFieldName;
|
||||||
|
if (jsonField != null && !Strings.isBlank(jsonFieldName = jsonField.name())) {
|
||||||
|
fieldName = jsonFieldName;
|
||||||
|
}
|
||||||
|
config.put(fieldName, desensitize);
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
package com.orion.ops.framework.desensitize.core.handler;
|
|
||||||
|
|
||||||
import com.orion.lang.define.wrapper.Wrapper;
|
|
||||||
import com.orion.ops.framework.common.constant.ResponseAdviceOrderConst;
|
|
||||||
import com.orion.ops.framework.common.annotation.DoDesensitize;
|
|
||||||
import com.orion.ops.framework.desensitize.core.processor.IDesensitizeProcessor;
|
|
||||||
import com.orion.ops.framework.desensitize.core.processor.ObjectDesensitizeProcessor;
|
|
||||||
import com.orion.ops.framework.desensitize.core.processor.WrapperDesensitizeProcessor;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.springframework.core.MethodParameter;
|
|
||||||
import org.springframework.core.annotation.Order;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.http.server.ServerHttpRequest;
|
|
||||||
import org.springframework.http.server.ServerHttpResponse;
|
|
||||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回结果脱敏处理器
|
|
||||||
*
|
|
||||||
* @author Jiahang Li
|
|
||||||
* @version 1.0.0
|
|
||||||
* @since 2023/6/15 17:38
|
|
||||||
*/
|
|
||||||
@Order(ResponseAdviceOrderConst.DESENSITIZE)
|
|
||||||
@ControllerAdvice
|
|
||||||
public class DesensitizeResultHandler implements ResponseBodyAdvice<Object> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(MethodParameter methodParameter, @NotNull Class converterType) {
|
|
||||||
return methodParameter.hasMethodAnnotation(DoDesensitize.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object beforeBodyWrite(Object body, @NotNull MethodParameter methodParameter, @NotNull MediaType selectedContentType, @NotNull Class selectedConverterType,
|
|
||||||
@NotNull ServerHttpRequest request, @NotNull ServerHttpResponse response) {
|
|
||||||
IDesensitizeProcessor processor;
|
|
||||||
if (body instanceof Wrapper<?>) {
|
|
||||||
// wrapper
|
|
||||||
processor = new WrapperDesensitizeProcessor();
|
|
||||||
} else {
|
|
||||||
// 普通对象
|
|
||||||
processor = new ObjectDesensitizeProcessor();
|
|
||||||
}
|
|
||||||
// 执行脱敏
|
|
||||||
processor.execute(body);
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package com.orion.ops.framework.desensitize.core.processor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 脱敏处理器
|
|
||||||
*
|
|
||||||
* @author Jiahang Li
|
|
||||||
* @version 1.0.0
|
|
||||||
* @since 2023/6/29 17:50
|
|
||||||
*/
|
|
||||||
public interface IDesensitizeProcessor<T> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 脱敏操作
|
|
||||||
*
|
|
||||||
* @param data data
|
|
||||||
*/
|
|
||||||
void execute(T data);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
package com.orion.ops.framework.desensitize.core.processor;
|
|
||||||
|
|
||||||
import com.orion.lang.utils.reflect.Annotations;
|
|
||||||
import com.orion.lang.utils.reflect.Methods;
|
|
||||||
import com.orion.ops.framework.common.utils.Desensitizes;
|
|
||||||
import com.orion.ops.framework.common.annotation.Desensitize;
|
|
||||||
import com.orion.ops.framework.common.annotation.DoDesensitize;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对象脱敏处理器
|
|
||||||
*
|
|
||||||
* @author Jiahang Li
|
|
||||||
* @version 1.0.0
|
|
||||||
* @since 2023/6/29 17:21
|
|
||||||
*/
|
|
||||||
public class ObjectDesensitizeProcessor implements IDesensitizeProcessor<Object> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(Object data) {
|
|
||||||
if (data == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Class<?> dataClass = data.getClass();
|
|
||||||
// 获取被标注脱敏的字段
|
|
||||||
Map<Field, Desensitize> annotatedFields = Annotations.getAnnotatedFields(dataClass, Desensitize.class, true);
|
|
||||||
annotatedFields.forEach((f, d) -> {
|
|
||||||
// 获取 getter 方法
|
|
||||||
Method getter = Methods.getGetterMethodByCache(dataClass, f.getName());
|
|
||||||
if (!getter.getReturnType().equals(String.class)) {
|
|
||||||
// 非 string 不进行脱敏操作
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 调用 getter 方法
|
|
||||||
String value = Methods.invokeMethod(data, getter);
|
|
||||||
if (value == null) {
|
|
||||||
// 为 null 不进行脱敏操作
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 数据脱敏
|
|
||||||
String desensitizeValue = this.valueDesensitize(value, d);
|
|
||||||
// 获取 setter 方法
|
|
||||||
Method setter = Methods.getSetterMethodByCache(dataClass, f.getName());
|
|
||||||
// 调用 setter 方法
|
|
||||||
Methods.invokeMethod(data, setter, desensitizeValue);
|
|
||||||
});
|
|
||||||
// 获取被标注脱敏字段的对象
|
|
||||||
Map<Field, DoDesensitize> annotatedObjects = Annotations.getAnnotatedFields(dataClass, DoDesensitize.class, true);
|
|
||||||
annotatedObjects.forEach((f, d) -> {
|
|
||||||
// 获取 getter 方法
|
|
||||||
Method getter = Methods.getGetterMethodByCache(dataClass, f.getName());
|
|
||||||
// 调用 getter 方法
|
|
||||||
Object value = Methods.invokeMethod(data, getter);
|
|
||||||
if (value == null) {
|
|
||||||
// 为 null 不进行脱敏操作
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 执行对象脱敏操作
|
|
||||||
this.execute(value);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数据脱敏
|
|
||||||
*
|
|
||||||
* @param value value
|
|
||||||
* @param c 配置
|
|
||||||
* @return 脱敏字符
|
|
||||||
*/
|
|
||||||
private String valueDesensitize(String value, Desensitize c) {
|
|
||||||
return Desensitizes.mix(value, c.keepStart(), c.keepEnd(), c.replacer());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package com.orion.ops.framework.desensitize.core.processor;
|
|
||||||
|
|
||||||
import com.orion.lang.define.wrapper.HttpWrapper;
|
|
||||||
import com.orion.lang.define.wrapper.RpcWrapper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* wrapper 对象脱敏处理器
|
|
||||||
*
|
|
||||||
* @author Jiahang Li
|
|
||||||
* @version 1.0.0
|
|
||||||
* @since 2023/6/29 18:17
|
|
||||||
*/
|
|
||||||
public class WrapperDesensitizeProcessor extends ObjectDesensitizeProcessor {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(Object data) {
|
|
||||||
if (data instanceof HttpWrapper<?>) {
|
|
||||||
super.execute(((HttpWrapper<?>) data).getData());
|
|
||||||
} else if (data instanceof RpcWrapper<?>) {
|
|
||||||
super.execute(data);
|
|
||||||
} else {
|
|
||||||
super.execute(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -69,12 +69,12 @@ public class OrionWebAutoConfiguration implements WebMvcConfigurer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return http message 转换器
|
* @return http message json 转换器
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public HttpMessageConverters fastJsonHttpMessageConverters() {
|
public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
|
||||||
// json 转换器
|
// json 转换器
|
||||||
FastJsonHttpMessageConverter jsonConverter = new FastJsonHttpMessageConverter();
|
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
|
||||||
// 配置
|
// 配置
|
||||||
FastJsonConfig config = new FastJsonConfig();
|
FastJsonConfig config = new FastJsonConfig();
|
||||||
// 支持的类型
|
// 支持的类型
|
||||||
@@ -86,7 +86,7 @@ public class OrionWebAutoConfiguration implements WebMvcConfigurer {
|
|||||||
MediaType.TEXT_HTML,
|
MediaType.TEXT_HTML,
|
||||||
MediaType.TEXT_XML
|
MediaType.TEXT_XML
|
||||||
);
|
);
|
||||||
jsonConverter.setSupportedMediaTypes(mediaTypes);
|
converter.setSupportedMediaTypes(mediaTypes);
|
||||||
// 序列化配置
|
// 序列化配置
|
||||||
config.setSerializerFeatures(
|
config.setSerializerFeatures(
|
||||||
SerializerFeature.DisableCircularReferenceDetect,
|
SerializerFeature.DisableCircularReferenceDetect,
|
||||||
@@ -94,7 +94,15 @@ public class OrionWebAutoConfiguration implements WebMvcConfigurer {
|
|||||||
SerializerFeature.WriteNullListAsEmpty,
|
SerializerFeature.WriteNullListAsEmpty,
|
||||||
SerializerFeature.IgnoreNonFieldGetter
|
SerializerFeature.IgnoreNonFieldGetter
|
||||||
);
|
);
|
||||||
jsonConverter.setFastJsonConfig(config);
|
converter.setFastJsonConfig(config);
|
||||||
|
return converter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return http message 转换器列表
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public HttpMessageConverters httpMessageConverters(FastJsonHttpMessageConverter jsonConverter) {
|
||||||
// 先获取默认转换器
|
// 先获取默认转换器
|
||||||
List<HttpMessageConverter<?>> defaultConverters = new HttpMessageConverters().getConverters();
|
List<HttpMessageConverter<?>> defaultConverters = new HttpMessageConverters().getConverters();
|
||||||
List<HttpMessageConverter<?>> converters = new ArrayList<>();
|
List<HttpMessageConverter<?>> converters = new ArrayList<>();
|
||||||
|
|||||||
Reference in New Issue
Block a user