|
|
@@ -0,0 +1,70 @@
|
|
|
+package shop.alien.config.advice;
|
|
|
+
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.core.MethodParameter;
|
|
|
+import org.springframework.http.HttpHeaders;
|
|
|
+import org.springframework.http.HttpInputMessage;
|
|
|
+import org.springframework.http.converter.HttpMessageConverter;
|
|
|
+import org.springframework.util.StreamUtils;
|
|
|
+import org.springframework.web.bind.annotation.ControllerAdvice;
|
|
|
+import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;
|
|
|
+import shop.alien.config.properties.EncryptProperties;
|
|
|
+import shop.alien.util.encryption.Decrypt;
|
|
|
+import shop.alien.util.encryption.StandardAesUtil;
|
|
|
+
|
|
|
+import java.io.ByteArrayInputStream;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.lang.reflect.Type;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 请求体解密 Advice
|
|
|
+ * 拦截带有 @Decrypt 注解的控制器方法,自动解密 AES 加密的请求体
|
|
|
+ */
|
|
|
+@ControllerAdvice
|
|
|
+public class DecryptRequestBodyAdvice extends RequestBodyAdviceAdapter {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private EncryptProperties encryptProperties;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
|
|
|
+ // 只有开启了配置,且方法或类上有 @Decrypt 注解时才拦截
|
|
|
+ return encryptProperties.isEnabled() &&
|
|
|
+ (methodParameter.hasMethodAnnotation(Decrypt.class) ||
|
|
|
+ methodParameter.getContainingClass().isAnnotationPresent(Decrypt.class));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
|
|
|
+ // 读取加密的请求体
|
|
|
+ byte[] bodyBytes = StreamUtils.copyToByteArray(inputMessage.getBody());
|
|
|
+ String encryptedData = new String(bodyBytes, StandardCharsets.UTF_8);
|
|
|
+
|
|
|
+ // 如果是 JSON 字符串格式(带有双引号),先去掉前后的双引号
|
|
|
+ if (encryptedData.startsWith("\"") && encryptedData.endsWith("\"")) {
|
|
|
+ encryptedData = encryptedData.substring(1, encryptedData.length() - 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 执行 AES 解密
|
|
|
+ String decryptedData = StandardAesUtil.decrypt(encryptedData, encryptProperties.getKey(), encryptProperties.getIv());
|
|
|
+
|
|
|
+ if (decryptedData == null) {
|
|
|
+ throw new RuntimeException("请求数据解密失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 返回解密后的输入流供后续 Jackson/Fastjson 解析
|
|
|
+ return new HttpInputMessage() {
|
|
|
+ @Override
|
|
|
+ public InputStream getBody() throws IOException {
|
|
|
+ return new ByteArrayInputStream(decryptedData.getBytes(StandardCharsets.UTF_8));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public HttpHeaders getHeaders() {
|
|
|
+ return inputMessage.getHeaders();
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+}
|