修改 http message 序列化方式 (fastjson -> jackson).

This commit is contained in:
lijiahang
2023-07-12 10:11:56 +08:00
parent 5c8681599b
commit be2d72d483
11 changed files with 102 additions and 167 deletions

View File

@@ -1,14 +1,13 @@
package com.orion.ops.framework.desensitize.config; package com.orion.ops.framework.desensitize.config;
import com.alibaba.fastjson.serializer.SerializeFilter; import com.orion.ops.framework.common.constant.AutoConfigureOrderConst;
import com.alibaba.fastjson.support.config.FastJsonConfig; import com.orion.ops.framework.desensitize.core.filter.DesensitizeValueFilter;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; import com.orion.ops.framework.desensitize.core.serializer.DesensitizeJsonSerializer;
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.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
/** /**
* 数据脱敏置类 * 数据脱敏置类
@@ -20,32 +19,25 @@ import org.springframework.context.annotation.Bean;
* @since 2023/6/29 16:55 * @since 2023/6/29 16:55
*/ */
@AutoConfiguration @AutoConfiguration
@AutoConfigureAfter(name = "com.orion.ops.framework.web.config.OrionWebAutoConfiguration") @AutoConfigureOrder(AutoConfigureOrderConst.FRAMEWORK_DESENSITIZE)
public class OrionDesensitizeAutoConfiguration { public class OrionDesensitizeAutoConfiguration {
/** /**
* @return 返回 序列化脱敏过滤器 * @return fastjson 序列化脱敏过滤器
*/ */
@Bean @Bean
@ConditionalOnBean(FastJsonHttpMessageConverter.class) public DesensitizeValueFilter desensitizeValueFilter() {
public DesensitizeValueSerializeFilter desensitizeValueSerializeFilter(FastJsonHttpMessageConverter converter) { return new DesensitizeValueFilter();
DesensitizeValueSerializeFilter desensitizeFilter = new DesensitizeValueSerializeFilter(); }
// 获取 json 配置
FastJsonConfig config = converter.getFastJsonConfig(); /**
SerializeFilter[] filters = config.getSerializeFilters(); * @return jackson 序列化脱敏过滤器
int filterLength = Arrays1.length(filters); */
if (filterLength == 0) { @Bean
// 未设置配置 @ConditionalOnBean(MappingJackson2HttpMessageConverter.class)
filters = new SerializeFilter[]{desensitizeFilter}; public DesensitizeJsonSerializer desensitizeJsonSerializer(MappingJackson2HttpMessageConverter converter) {
} else { DesensitizeJsonSerializer serializer = new DesensitizeJsonSerializer();
SerializeFilter[] newFilters = new SerializeFilter[filterLength + 1]; return serializer;
System.arraycopy(filters, 0, newFilters, 0, filterLength);
newFilters[filterLength] = desensitizeFilter;
filters = newFilters;
}
// 更新到配置
config.setSerializeFilters(filters);
return desensitizeFilter;
} }
} }

View File

@@ -1,4 +1,8 @@
package com.orion.ops.framework.common.annotation; package com.orion.ops.framework.desensitize.core.annotation;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.orion.ops.framework.desensitize.core.serializer.DesensitizeJsonSerializer;
import java.lang.annotation.*; import java.lang.annotation.*;
@@ -14,6 +18,8 @@ import java.lang.annotation.*;
@Target({ElementType.FIELD}) @Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
@JacksonAnnotationsInside
@JsonSerialize(using = DesensitizeJsonSerializer.class)
public @interface Desensitize { public @interface Desensitize {
/** /**

View File

@@ -1,4 +1,4 @@
package com.orion.ops.framework.common.annotation; package com.orion.ops.framework.desensitize.core.annotation;
import java.lang.annotation.*; import java.lang.annotation.*;

View File

@@ -8,8 +8,8 @@ import com.orion.lang.utils.Strings;
import com.orion.lang.utils.collect.Maps; import com.orion.lang.utils.collect.Maps;
import com.orion.lang.utils.reflect.Annotations; import com.orion.lang.utils.reflect.Annotations;
import com.orion.lang.utils.reflect.Fields; import com.orion.lang.utils.reflect.Fields;
import com.orion.ops.framework.common.annotation.Desensitize; import com.orion.ops.framework.desensitize.core.annotation.Desensitize;
import com.orion.ops.framework.common.annotation.DesensitizeObject; import com.orion.ops.framework.desensitize.core.annotation.DesensitizeObject;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.HashMap; import java.util.HashMap;
@@ -17,13 +17,15 @@ import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* 脱敏序列化器 * fastjson 脱敏序列化器
* <p>
* 用于全局日志打印
* *
* @author Jiahang Li * @author Jiahang Li
* @version 1.0.0 * @version 1.0.0
* @since 2023/6/30 12:19 * @since 2023/6/30 12:19
*/ */
public class DesensitizeValueSerializeFilter implements ValueFilter { public class DesensitizeValueFilter implements ValueFilter {
private static final Map<String, Map<String, Desensitize>> DESENSITIZE_FIELDS = new HashMap<>(); private static final Map<String, Map<String, Desensitize>> DESENSITIZE_FIELDS = new HashMap<>();
@@ -32,7 +34,7 @@ public class DesensitizeValueSerializeFilter implements ValueFilter {
if (object == null || value == null) { if (object == null || value == null) {
return value; return value;
} }
Desensitize config = doDesensitizeField(object, name); Desensitize config = this.doDesensitizeField(object, name);
// 无需脱敏 // 无需脱敏
if (config == null) { if (config == null) {
return value; return value;

View File

@@ -0,0 +1,52 @@
package com.orion.ops.framework.desensitize.core.serializer;
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.orion.lang.utils.Desensitizes;
import com.orion.lang.utils.Objects1;
import com.orion.ops.framework.desensitize.core.annotation.Desensitize;
import java.io.IOException;
import java.util.Objects;
/**
* jackson 脱敏序列化器
* <p>
* 用于 http 响应
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/11 17:10
*/
public class DesensitizeJsonSerializer extends JsonSerializer<Object> implements ContextualSerializer {
private Desensitize desensitize;
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
Desensitize desensitize = property.getAnnotation(Desensitize.class);
if (Objects.nonNull(desensitize)) {
this.desensitize = desensitize;
return this;
}
return prov.findValueSerializer(property.getType(), property);
}
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
// 为空判断
if (value == null) {
gen.writeNull();
return;
}
// 脱敏
String mix = Desensitizes.mix(Objects1.toString(value), desensitize.keepStart(), desensitize.keepEnd(), desensitize.replacer());
gen.writeString(mix);
}
}

View File

@@ -62,8 +62,8 @@ public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterce
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
@Autowired(required = false) @Autowired(required = false)
@Qualifier("desensitizeValueSerializeFilter") @Qualifier("desensitizeValueFilter")
private ValueFilter desensitizeValueSerializeFilter; private ValueFilter desensitizeValueFilter;
public AbstractLogPrinterInterceptor(LogPrinterConfig config) { public AbstractLogPrinterInterceptor(LogPrinterConfig config) {
this.config = config; this.config = config;
@@ -89,8 +89,8 @@ public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterce
fieldFilterList.add(ignoreFilter); fieldFilterList.add(ignoreFilter);
fieldFilterList.add(desensitizeFilter); fieldFilterList.add(desensitizeFilter);
// 注解脱敏 未引入 // 注解脱敏 未引入
if (desensitizeValueSerializeFilter != null) { if (desensitizeValueFilter != null) {
fieldFilterList.add(desensitizeValueSerializeFilter); fieldFilterList.add(desensitizeValueFilter);
} }
this.fieldFilters = fieldFilterList.toArray(new SerializeFilter[0]); this.fieldFilters = fieldFilterList.toArray(new SerializeFilter[0]);
} }

View File

@@ -1,30 +1,27 @@
package com.orion.ops.framework.web.config; package com.orion.ops.framework.web.config;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.orion.lang.utils.collect.Lists; import com.orion.lang.utils.collect.Lists;
import com.orion.ops.framework.common.constant.AutoConfigureOrderConst;
import com.orion.ops.framework.common.constant.FilterOrderConst; import com.orion.ops.framework.common.constant.FilterOrderConst;
import com.orion.ops.framework.common.filter.FilterCreator; import com.orion.ops.framework.common.filter.FilterCreator;
import com.orion.ops.framework.web.core.convert.CustomerFastJsonHttpMessageConverter;
import com.orion.ops.framework.web.core.convert.SerializeConfig;
import com.orion.ops.framework.web.core.filter.TraceIdFilter; import com.orion.ops.framework.web.core.filter.TraceIdFilter;
import com.orion.ops.framework.web.core.handler.GlobalExceptionHandler; import com.orion.ops.framework.web.core.handler.GlobalExceptionHandler;
import com.orion.ops.framework.web.core.handler.WrapperResultHandler; import com.orion.ops.framework.web.core.handler.WrapperResultHandler;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.converter.ByteArrayHttpMessageConverter; import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceRegionHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.util.AntPathMatcher; import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@@ -48,7 +45,7 @@ import java.util.List;
* @since 2023/6/16 16:26 * @since 2023/6/16 16:26
*/ */
@AutoConfiguration @AutoConfiguration
@EnableConfigurationProperties(SerializeConfig.class) @AutoConfigureOrder(AutoConfigureOrderConst.FRAMEWORK_WEB)
public class OrionWebAutoConfiguration implements WebMvcConfigurer { public class OrionWebAutoConfiguration implements WebMvcConfigurer {
@Value("${orion.api.prefix}") @Value("${orion.api.prefix}")
@@ -78,39 +75,6 @@ public class OrionWebAutoConfiguration implements WebMvcConfigurer {
return new WrapperResultHandler(); return new WrapperResultHandler();
} }
/**
* @param serializeConfig 序列化配置
* @return http message fast json 转换器
*/
@Bean
public FastJsonHttpMessageConverter fastJsonHttpMessageConverter(SerializeConfig serializeConfig) {
// json 转换器
CustomerFastJsonHttpMessageConverter converter = new CustomerFastJsonHttpMessageConverter(serializeConfig);
// 配置
FastJsonConfig config = new FastJsonConfig();
// 支持的类型
List<MediaType> mediaTypes = Lists.of(
MediaType.APPLICATION_JSON,
MediaType.APPLICATION_FORM_URLENCODED,
MediaType.APPLICATION_XHTML_XML,
MediaType.TEXT_PLAIN,
MediaType.TEXT_HTML,
MediaType.TEXT_XML
);
converter.setSupportedMediaTypes(mediaTypes);
// 序列化配置
config.setSerializerFeatures(
SerializerFeature.DisableCircularReferenceDetect,
SerializerFeature.WriteMapNullValue,
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.IgnoreNonFieldGetter
);
config.setCharset(StandardCharsets.UTF_8);
converter.setFastJsonConfig(config);
converter.setDefaultCharset(StandardCharsets.UTF_8);
return converter;
}
/** /**
* @return http message jackson 转换器 * @return http message jackson 转换器
*/ */
@@ -125,9 +89,11 @@ public class OrionWebAutoConfiguration implements WebMvcConfigurer {
MediaType.TEXT_PLAIN, MediaType.TEXT_PLAIN,
MediaType.TEXT_HTML, MediaType.TEXT_HTML,
MediaType.TEXT_XML, MediaType.TEXT_XML,
new MediaType("application", "vnd.spring-boot.actuator.v2+json") MediaType.ALL
); );
converter.setSupportedMediaTypes(mediaTypes); converter.setSupportedMediaTypes(mediaTypes);
converter.setDefaultCharset(StandardCharsets.UTF_8);
// 默认 objectMapper
ObjectMapper objectMapper = converter.getObjectMapper(); ObjectMapper objectMapper = converter.getObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 序列化配置 // 序列化配置
@@ -142,18 +108,14 @@ public class OrionWebAutoConfiguration implements WebMvcConfigurer {
* @return http message 转换器列表 * @return http message 转换器列表
*/ */
@Bean @Bean
public HttpMessageConverters httpMessageConverters(FastJsonHttpMessageConverter fastJsonConverter, public HttpMessageConverters httpMessageConverters(MappingJackson2HttpMessageConverter jacksonConvert) {
MappingJackson2HttpMessageConverter jacksonConvert) {
List<HttpMessageConverter<?>> defaultConverters = new HttpMessageConverters().getConverters();
List<HttpMessageConverter<?>> converters = new ArrayList<>(); List<HttpMessageConverter<?>> converters = new ArrayList<>();
// byte converter 添加至首位 - fix swagger api 返回base64报错 // 添加 byte converter - swagger api
converters.add(new ByteArrayHttpMessageConverter()); converters.add(new ByteArrayHttpMessageConverter());
// 添加自定义 converter - using WrapperResultHandler/脱敏 // 添加 resource region - admin api log
converters.add(fastJsonConverter); converters.add(new ResourceRegionHttpMessageConverter());
// 添加自定义 converter - jackson // 添加 json converter - jackson
converters.add(jacksonConvert); converters.add(jacksonConvert);
// 添加默认处理器
converters.addAll(defaultConverters);
return new HttpMessageConverters(false, converters); return new HttpMessageConverters(false, converters);
} }

View File

@@ -1,40 +0,0 @@
package com.orion.ops.framework.web.core.convert;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.http.MediaType;
import java.lang.reflect.Type;
import java.util.List;
/**
* 自定义 fastjson 转换器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/11 11:46
*/
public class CustomerFastJsonHttpMessageConverter extends FastJsonHttpMessageConverter {
private final SerializeConfig serializeConfig;
public CustomerFastJsonHttpMessageConverter(SerializeConfig serializeConfig) {
this.serializeConfig = serializeConfig;
}
@Override
public boolean canRead(Type type, Class<?> contextClass, MediaType mediaType) {
List<String> unsupportedClasses = serializeConfig.getUnsupportedClasses();
if (unsupportedClasses != null) {
if (unsupportedClasses.contains(contextClass.getName())) {
return false;
}
}
return super.canRead(type, contextClass, mediaType);
}
@Override
public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
return super.canWrite(type, clazz, mediaType);
}
}

View File

@@ -1,29 +0,0 @@
package com.orion.ops.framework.web.core.convert;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.ArrayList;
import java.util.List;
/**
* 序列化配置
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/11 14:57
*/
@Data
@ConfigurationProperties("orion.serializer")
public class SerializeConfig {
/**
* 不支持的序列化类型
*/
private List<String> unsupportedClasses;
public SerializeConfig() {
this.unsupportedClasses = new ArrayList<>();
}
}

View File

@@ -14,11 +14,6 @@
"name": "orion.api.cors", "name": "orion.api.cors",
"type": "java.lang.Boolean", "type": "java.lang.Boolean",
"description": "是否开启 cors 过滤器." "description": "是否开启 cors 过滤器."
},
{
"name": "orion.serializer.unsupported-classes",
"type": "java.util.List",
"description": "不支持的序列化类型."
} }
] ]
} }

View File

@@ -133,11 +133,6 @@ orion:
prefix: /orion-api prefix: /orion-api
# 是否开启跨域 # 是否开启跨域
cors: true cors: true
serializer:
# 不支持的序列化类型
unsupported-classes:
- de.codecentric.boot.admin.server.web.InstancesController
- org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler
swagger: swagger:
# swagger 配置 # swagger 配置
title: orion-ops-pro 运维平台 title: orion-ops-pro 运维平台