Browse Source

feat(third-party): 增强第三方接口日志及数据解密功能

- 在配置文件中新增第三方JWT认证密钥与过期时间配置
- 扩展第三方接口URL白名单配置,支持特定接口独立过滤链
- EquipChargeStatusResponseVO增加B、C相电流和电压字段
- ThirdPartyApiLog实体新增接口中文说明及解密后的请求和响应数据字段
- 第三方接口日志切面完善:添加接口中文说明获取功能
- 实现请求和响应数据解密方法,支持RequestParmsEntity和ResponseParmsEntity类型
- 解密采用系统统一密钥和初始向量,异常时记录警告日志
- 根据请求URI智能返回接口中文说明,便于日志和监控展示
SheepHy 6 days ago
parent
commit
e8331fe5b6

+ 110 - 0
src/main/java/com/zsElectric/boot/charging/aspect/ThirdPartyApiLogAspect.java

@@ -5,6 +5,10 @@ import cn.hutool.json.JSONUtil;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.zsElectric.boot.charging.entity.ThirdPartyApiLog;
 import com.zsElectric.boot.charging.service.ThirdPartyApiLogService;
+import com.zsElectric.boot.common.constant.ConnectivityConstants;
+import com.zsElectric.boot.common.util.AESCryptoUtils;
+import com.zsElectric.boot.common.util.electric.RequestParmsEntity;
+import com.zsElectric.boot.common.util.electric.ResponseParmsEntity;
 import jakarta.servlet.http.HttpServletRequest;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -91,6 +95,7 @@ public class ThirdPartyApiLogAspect {
                 apiLog.setRequestMethod(request.getMethod());
                 apiLog.setRequestUrl(request.getRequestURL().toString());
                 apiLog.setInterfaceName(request.getRequestURI());
+                apiLog.setInterfaceDescription(getInterfaceDescription(request.getRequestURI()));
                 apiLog.setClientIp(getClientIp(request));
                 apiLog.setUserAgent(request.getHeader("User-Agent"));
                 
@@ -112,6 +117,9 @@ public class ThirdPartyApiLogAspect {
                             
                             // 尝试提取业务字段
                             extractBusinessFields(arg, apiLog);
+                            
+                            // 尝试解密请求数据(针对 RequestParmsEntity 类型)
+                            decryptRequestData(arg, apiLog);
                             break;
                         }
                     }
@@ -129,6 +137,9 @@ public class ThirdPartyApiLogAspect {
             
             if (result != null) {
                 apiLog.setResponseBody(objectMapper.writeValueAsString(result));
+                
+                // 尝试解密响应数据(针对 ResponseParmsEntity 类型)
+                decryptResponseData(result, apiLog);
             }
             
             // 异步保存日志
@@ -151,6 +162,62 @@ public class ThirdPartyApiLogAspect {
         }
     }
 
+    /**
+     * 解密请求数据
+     * 针对 LinkDataController 接收的 RequestParmsEntity 类型参数进行解密
+     */
+    private void decryptRequestData(Object requestBody, ThirdPartyApiLog apiLog) {
+        try {
+            // 判断是否为 RequestParmsEntity 类型
+            if (requestBody instanceof RequestParmsEntity) {
+                RequestParmsEntity requestParms = (RequestParmsEntity) requestBody;
+                String encryptedData = requestParms.getData();
+                
+                if (StrUtil.isNotBlank(encryptedData)) {
+                    // 使用系统密钥解密
+                    String decryptedData = AESCryptoUtils.decrypt(
+                        encryptedData, 
+                        ConnectivityConstants.DATA_SECRET, 
+                        ConnectivityConstants.DATA_SECRET_IV
+                    );
+                    
+                    apiLog.setDecryptedRequestData(decryptedData);
+                    log.debug("请求数据解密成功: {}", decryptedData);
+                }
+            }
+        } catch (Exception e) {
+            log.warn("解密请求数据失败: {}", e.getMessage());
+        }
+    }
+
+    /**
+     * 解密响应数据
+     * 针对返回的 ResponseParmsEntity 类型响应进行解密
+     */
+    private void decryptResponseData(Object responseBody, ThirdPartyApiLog apiLog) {
+        try {
+            // 判断是否为 ResponseParmsEntity 类型
+            if (responseBody instanceof ResponseParmsEntity) {
+                ResponseParmsEntity responseParms = (ResponseParmsEntity) responseBody;
+                String encryptedData = responseParms.getData();
+                
+                if (StrUtil.isNotBlank(encryptedData)) {
+                    // 使用系统密钥解密
+                    String decryptedData = AESCryptoUtils.decrypt(
+                        encryptedData, 
+                        ConnectivityConstants.DATA_SECRET, 
+                        ConnectivityConstants.DATA_SECRET_IV
+                    );
+                    
+                    apiLog.setDecryptedResponseData(decryptedData);
+                    log.debug("响应数据解密成功: {}", decryptedData);
+                }
+            }
+        } catch (Exception e) {
+            log.warn("解密响应数据失败: {}", e.getMessage());
+        }
+    }
+
     /**
      * 提取业务字段
      */
@@ -218,6 +285,49 @@ public class ThirdPartyApiLogAspect {
         }
     }
 
+    /**
+     * 获取接口中文说明
+     * 根据接口路径返回对应的中文说明
+     */
+    private String getInterfaceDescription(String uri) {
+        if (StrUtil.isBlank(uri)) {
+            return null;
+        }
+        
+        // LinkDataController 接口说明
+        if (uri.contains("/query_token")) {
+            return "获取token";
+        } else if (uri.contains("/notification_start_charge_result")) {
+            return "推送启动充电结果";
+        } else if (uri.contains("/notification_equip_charge_status")) {
+            return "推送充电状态";
+        } else if (uri.contains("/notification_stop_charge_result")) {
+            return "推送停止充电结果";
+        } else if (uri.contains("/notification_charge_order_info")) {
+            return "推送充电订单信息";
+        } else if (uri.contains("/notification_stationStatus")) {
+            return "设备状态变化推送";
+        }
+        // ChargingBusinessController 接口说明
+        else if (uri.contains("/queryEquipBusinessPolicy")) {
+            return "查询业务策略信息";
+        } else if (uri.contains("/queryEquipAuth")) {
+            return "请求设备认证";
+        } else if (uri.contains("/queryStationsInfo")) {
+            return "查询充电站信息";
+        } else if (uri.contains("/queryStationStatus")) {
+            return "设备接口状态查询";
+        } else if (uri.contains("/startCharging")) {
+            return "请求启动充电";
+        } else if (uri.contains("/queryChargingStatus")) {
+            return "查询充电状态";
+        } else if (uri.contains("/stopCharging")) {
+            return "请求停止充电";
+        }
+        
+        return null;
+    }
+
     /**
      * 获取客户端真实IP
      */

+ 18 - 0
src/main/java/com/zsElectric/boot/charging/entity/ThirdPartyApiLog.java

@@ -44,6 +44,12 @@ public class ThirdPartyApiLog implements Serializable {
     @TableField("interface_name")
     private String interfaceName;
 
+    /**
+     * 接口中文说明
+     */
+    @TableField("interface_description")
+    private String interfaceDescription;
+
     /**
      * 请求方法(GET/POST等)
      */
@@ -74,6 +80,12 @@ public class ThirdPartyApiLog implements Serializable {
     @TableField("request_body")
     private String requestBody;
 
+    /**
+     * 解密后的请求数据内容(仅加密接口)
+     */
+    @TableField("decrypted_request_data")
+    private String decryptedRequestData;
+
     /**
      * 响应状态码
      */
@@ -92,6 +104,12 @@ public class ThirdPartyApiLog implements Serializable {
     @TableField("response_body")
     private String responseBody;
 
+    /**
+     * 解密后的响应数据内容(仅加密接口)
+     */
+    @TableField("decrypted_response_data")
+    private String decryptedResponseData;
+
     /**
      * 响应耗时(毫秒)
      */

+ 16 - 0
src/main/java/com/zsElectric/boot/charging/vo/EquipChargeStatusResponseVO.java

@@ -34,10 +34,26 @@ public class EquipChargeStatusResponseVO {
     @JsonProperty("CurrentA")
     private BigDecimal CurrentA;
 
+    @Schema(description = "B相电流,单位:A", example = "15.5")
+    @JsonProperty("CurrentB")
+    private BigDecimal CurrentB;
+
+    @Schema(description = "C相电流,单位:A", example = "15.5")
+    @JsonProperty("CurrentC")
+    private BigDecimal CurrentC;
+
     @Schema(description = "A相电压,单位:V", example = "220.0", required = true)
     @JsonProperty("VoltageA")
     private BigDecimal VoltageA;
 
+    @Schema(description = "B相电压,单位:V", example = "220.0")
+    @JsonProperty("VoltageB")
+    private BigDecimal VoltageB;
+
+    @Schema(description = "C相电压,单位:V", example = "220.0")
+    @JsonProperty("VoltageC")
+    private BigDecimal VoltageC;
+
     @Schema(description = "荷电状态,0-100", example = "80", required = true)
     @JsonProperty("Soc")
     private Integer Soc;

+ 15 - 0
src/main/resources/application-prod.yml

@@ -50,6 +50,13 @@ spring:
             enable: true
     # 邮件发送者
     from: youlaitech@163.com
+
+# 第三方认证配置
+third-party:
+  jwt:
+    secret: "vgct1TZ4ZikKjaaeIiq3LUwIvpmcgYa6ABCD1234EFGH5678IJKL9012MNOP3456"
+    expire: 7200
+
 mybatis-plus:
   mapper-locations: classpath*:/mapper/**/*.xml
   global-config:
@@ -94,6 +101,14 @@ security:
     - /v3/api-docs/**
     - /webjars/**
     - /favicon.ico
+    - /dev/v1/linkData/**
+  # 只走第三方过滤器、不走其他安全链
+  third-party-urls:
+    - /dev/v1/linkData/notification_start_charge_result
+    - /dev/v1/linkData/notification_equip_charge_status
+    - /dev/v1/linkData/notification_stop_charge_result
+    - /dev/v1/linkData/notification_charge_order_info
+    - /dev/v1/linkData/notification_stationStatus
 
 # 文件存储配置
 oss: