|
@@ -0,0 +1,123 @@
|
|
|
+package com.xs.core.filter;
|
|
|
+
|
|
|
+import com.alibaba.fastjson2.JSON;
|
|
|
+import com.alibaba.fastjson2.JSONObject;
|
|
|
+import com.xs.core.common.constant.ConstantConfig;
|
|
|
+import com.xs.core.common.exception.BusinessException;
|
|
|
+import com.xs.core.model.ResponseResult;
|
|
|
+import com.xs.core.request.BodyRequestWrapper;
|
|
|
+import com.xs.core.request.RequestWrapper;
|
|
|
+import com.xs.core.utils.OpenApiEncryptionUtils;
|
|
|
+import com.xs.core.utils.SecurityUtil;
|
|
|
+import com.xs.core.utils.redis.RedissonLockUtil;
|
|
|
+import jakarta.servlet.*;
|
|
|
+import jakarta.servlet.http.HttpServletRequest;
|
|
|
+import jakarta.servlet.http.HttpServletResponse;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.springframework.core.annotation.Order;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 开放接口请求处理器 用于解密请求参数
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Component
|
|
|
+@Order(2)
|
|
|
+public class OpenApiRequestHandler implements Filter {
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
|
|
|
+ HttpServletRequest request = (HttpServletRequest) servletRequest;
|
|
|
+ HttpServletResponse response = (HttpServletResponse) servletResponse;
|
|
|
+ // 开放接口请求
|
|
|
+ String path = request.getServletPath();
|
|
|
+ if (!path.startsWith("/openapi/v1/")) {
|
|
|
+ chain.doFilter(request, response);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ log.info("开放接口请求过滤");
|
|
|
+ if (StringUtils.isNotBlank(request.getContentType()) && request.getContentType().contains("application/json")) {
|
|
|
+ RequestWrapper requestWrapper = new RequestWrapper(request);
|
|
|
+ // 拿到加密串
|
|
|
+ String data = requestWrapper.getBody();
|
|
|
+ data = data.replaceAll("\\s", "");
|
|
|
+ if (StringUtils.isBlank(data)) {
|
|
|
+ chain.doFilter(requestWrapper, response);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ JSONObject json = JSONObject.parseObject(data);
|
|
|
+ //验签
|
|
|
+ String encryptData = json.getString("encryptData");
|
|
|
+ if (!SecurityUtil.verifySign(encryptData, json.getString("identifying"))) {
|
|
|
+ byte[] results = _getErrorBytes(ResponseResult.failed("response.error.sign", null));
|
|
|
+ log.error("加密解析===》签名有误!");
|
|
|
+ servletResponse.setContentType("application/json; charset=UTF-8");
|
|
|
+ servletResponse.getOutputStream().write(results);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 解密
|
|
|
+ String result = OpenApiEncryptionUtils.aesDecrypt(encryptData);
|
|
|
+ // 请求有效性校验
|
|
|
+ JSONObject requestJson = JSONObject.parseObject(result);
|
|
|
+ if (!requestJson.containsKey("basicData")) {
|
|
|
+ byte[] results = _getErrorBytes(ResponseResult.failed("response.formatting.error", null));
|
|
|
+ log.error("加密解析===》请求参数有误!");
|
|
|
+ servletResponse.setContentType("application/json; charset=UTF-8");
|
|
|
+ servletResponse.getOutputStream().write(results);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ JSONObject basicJson = requestJson.getJSONObject("basicData");
|
|
|
+ if (!basicJson.containsKey("timeStamp") || !basicJson.containsKey("messageId")) {
|
|
|
+ byte[] results = _getErrorBytes(ResponseResult.failed("response.formatting.error", null));
|
|
|
+ log.error("加密解析===》请求参数有误!");
|
|
|
+ servletResponse.setContentType("application/json; charset=UTF-8");
|
|
|
+ servletResponse.getOutputStream().write(results);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 比对时间
|
|
|
+ if (System.currentTimeMillis() - basicJson.getLong("timeStamp") > 300000) {
|
|
|
+ log.error("加密解析===》更新当前设备时间为UTC标准时间!");
|
|
|
+ byte[] results = _getErrorBytes(ResponseResult.failed("response.error.timeout", null));
|
|
|
+ servletResponse.setContentType("application/json; charset=UTF-8");
|
|
|
+ servletResponse.getOutputStream().write(results);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 验证请求唯一性
|
|
|
+ String key = String.format("%s%s", ConstantConfig.MESSAGE_ID_PREFIX, basicJson.getString("messageId"));
|
|
|
+ try {
|
|
|
+ boolean tryLock = RedissonLockUtil.tryLock(key);
|
|
|
+ if (!tryLock) {
|
|
|
+ byte[] results = _getErrorBytes(ResponseResult.failed("response.error.repeat", null));
|
|
|
+ servletResponse.setContentType("application/json; charset=UTF-8");
|
|
|
+ servletResponse.getOutputStream().write(results);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ throw new BusinessException("验证请求唯一性发生异常");
|
|
|
+ }
|
|
|
+ if (!requestJson.containsKey("bizData") ||
|
|
|
+ StringUtils.isBlank(requestJson.getString("bizData"))) {
|
|
|
+ request = new BodyRequestWrapper(request, "[]");
|
|
|
+ } else {
|
|
|
+ request = new BodyRequestWrapper(request, requestJson.getString("bizData"));
|
|
|
+ }
|
|
|
+ chain.doFilter(request, response);
|
|
|
+ } else {
|
|
|
+ chain.doFilter(request, response);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private byte[] _getErrorBytes(ResponseResult<?> responseResult) {
|
|
|
+ String result = OpenApiEncryptionUtils.aesEncrypt(JSON.toJSONString(responseResult));
|
|
|
+ String sign = SecurityUtil.getSign(result);
|
|
|
+ JSONObject jsonObject = new JSONObject();
|
|
|
+ jsonObject.put("encryptData", result);
|
|
|
+ jsonObject.put("identifying", sign);
|
|
|
+ return jsonObject.toJSONString().getBytes(StandardCharsets.UTF_8);
|
|
|
+
|
|
|
+ }
|
|
|
+}
|