自定义消息转换器对请求报文的统一解密处理
1.自定义拦截器Interceptor
package com.example.springbootdemo.config; import lombok.extern.slf4j.Slf4j; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Slf4j public class CustomInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } }
2.自定义sm4的加解密工具
package com.example.springbootdemo.util; import cn.hutool.crypto.SmUtil; import cn.hutool.crypto.symmetric.SM4; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSONObject; import com.example.springbootdemo.requet.LoginReq; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; public class SM4Util { private static final String key = "w5mqd1mv318stg2w"; public String getEncryptBase64(String jsonStr){ SM4 sm41 = SmUtil.sm4(key.getBytes()); String encryptHex = sm41.encryptHex(jsonStr); return encryptHex; } public String getDecryptStr(String EncryptBase64){ SM4 sm41 = SmUtil.sm4(key.getBytes()); String sourceDate = sm41.decryptStr(EncryptBase64); return sourceDate; } public static void main(String[] args) throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); //objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); LoginReq loginReq = new LoginReq(); loginReq.setUserName("zhangsan"); loginReq.setPassword("password123"); String s = objectMapper.writeValueAsString(loginReq); System.out.println(s); System.out.println(JSONUtil.toBean(s, LoginReq.class)); String jsonStr = JSONUtil.toJsonStr(loginReq); System.out.println(new SM4Util().getEncryptBase64(jsonStr)); String jsonString = JSONObject.toJSONString(loginReq); System.out.println(JSONUtil.toBean(jsonString, LoginReq.class)); System.out.println(s); } }
3.自定义JSON序列化配置
package com.example.springbootdemo.config; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; public class CommonLocalDateTimeSerializer extends JsonSerializer<LocalDateTime> { public static final String FULL_YMD_HMS_PATTERN = "yyyy-MM-dd HH:mm:ss"; public static final String ZONE_ID = "Asia/Shanghai"; @Override public void serialize(LocalDateTime dateTime, JsonGenerator gen, SerializerProvider serializers) throws IOException { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(FULL_YMD_HMS_PATTERN).withZone(ZoneId.of(ZONE_ID)); String format = dateTime.format(dateTimeFormatter); // dateTimeFormatter.format(dateTime); gen.writeString(format); } }
@Bean public ObjectMapper objectMapper(){ ObjectMapper objectMapper = new ObjectMapper(); objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // 自定义LocalDateTime类型数据的json序列化方式 JavaTimeModule javaTimeModule = new JavaTimeModule(); javaTimeModule.addSerializer(LocalDateTime.class, new CommonLocalDateTimeSerializer()); return objectMapper; }
4.自定义消息转换器
package com.example.springbootdemo.config; import cn.hutool.json.JSONUtil; import com.example.springbootdemo.requet.CommonRequest; import com.example.springbootdemo.util.SM4Util; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpOutputMessage; import org.springframework.http.MediaType; import org.springframework.http.converter.AbstractHttpMessageConverter; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotWritableException; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; @Slf4j public class CustomHttpMessageConverter extends AbstractHttpMessageConverter { private ObjectMapper objectMapper; private SM4Util sm4Util; private ThreadLocal<CommonRequest> threadLocal = new ThreadLocal<>(); public CustomHttpMessageConverter(ObjectMapper objectMapper, SM4Util sm4Util) { this.objectMapper = objectMapper; this.sm4Util = sm4Util; } @Override protected boolean supports(Class clazz) { return false; } /** *是否使用readInternal方法处理请求报文 * @return */ @Override public boolean canRead(Class clazz, MediaType mediaType) { return true; } @Override protected Object readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { InputStream body = inputMessage.getBody(); String reqBody = IOUtils.toString(body, StandardCharsets.US_ASCII); log.info("通用请求CommonRequest密文:{}", reqBody); CommonRequest request = this.objectMapper.reader().forType(CommonRequest.class).readValue(reqBody); String decryptStr = sm4Util.getDecryptStr(request.getReqJsonData()); log.info("通用请求CommonRequest解密报文:{}", decryptStr); request.setReqJsonData(decryptStr); threadLocal.set(request); return this.objectMapper.reader().forType(clazz).readValue(decryptStr); } /** *是否使用writeInternal方法处理响应报文 * @return */ @Override protected boolean canWrite(MediaType mediaType) { // 对某些请求使用或者不使用消息转换器 RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); request.getHeader("key1"); request.getRequestURI(); return false; } @Override protected void writeInternal(Object o, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { } }
5.定义WebMvcConfigurer
package com.example.springbootdemo.config; import com.example.springbootdemo.util.SM4Util; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.time.LocalDateTime; import java.util.Collections; import java.util.List; @Configuration @Slf4j @ConditionalOnProperty(prefix = "webMvc", value = { "enable" }, havingValue = "true") public class WebConfig implements WebMvcConfigurer { public CustomInterceptor customInterceptor(){ return new CustomInterceptor(); } @Bean public ObjectMapper objectMapper(){ ObjectMapper objectMapper = new ObjectMapper(); objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // 自定义LocalDateTime类型数据的json序列化方式 JavaTimeModule javaTimeModule = new JavaTimeModule(); javaTimeModule.addSerializer(LocalDateTime.class, new CommonLocalDateTimeSerializer()); return objectMapper; } @Bean public SM4Util sm4Util(){ return new SM4Util(); } @Override public void extendMessageConverters(List<HttpMessageConverter<?>> converters){ CustomHttpMessageConverter converter = new CustomHttpMessageConverter(objectMapper(), sm4Util()); converter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL)); converters.add(0, converter); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(customInterceptor()).addPathPatterns("/**"); } }
测试验证: