Sfoglia il codice sorgente

fix(omg-pay): 增强验签失败诊断日志,定位 CheckMacValue mismatch

线上日志确认问题B的根因不是 parseKvResponse(响应已被正确解析),
而是 verifyResponse 验签失败(CheckMacValue mismatch)——id=26 在
OMG 后台已授权,但 queryTrade 因验签失败读不到 TradeStatus,被 catch
吞成 {0,0} 判未付。原诊断 truncate(resp,500) 把 CheckMacValue 字段
本身截掉了,无法定位验签分歧。

- queryTrade 查询返回时打印完整 resp(info)
- 解析失败/验签失败 catch 去掉 500 截断,打印完整 resp
- 验签失败 catch 补全 receivedCMV(OMG回传)/computedCMV(本地重算)/
  脱敏 hashKey+hashIv/TradeStatus/RtnCode,一行 error 自包含排查信息
- 无用的 truncate helper 替换为 mask(凭证脱敏)

纯诊断增强,不改验签算法——等 receivedCMV vs computedCMV 对比
(及完整 resp 里的 CheckMacValue 原值)坐实分歧(疑大小写排序:
QueryTradeInfo 响应混合大小写字段 vs TreeMap 大小写敏感),再改。

Co-Authored-By: Claude <noreply@anthropic.com>
qmj 2 settimane fa
parent
commit
b16b4f1151

+ 19 - 6
ruoyi-admin/src/main/java/com/ruoyi/app/utils/omg/OmgPay.java

@@ -94,17 +94,27 @@ public class OmgPay {
         params.put("TimeStamp", String.valueOf(System.currentTimeMillis() / 1000L));
         params.put("CheckMacValue", OmgCheckMacValue.generate(params, cfg.getHashKey(), cfg.getHashIv()));
         String resp = postForm(endpoint(baseUrl, URL_QUERY_TRADE_INFO), params);
+        log.info("[OMG] queryTrade 查询返回 resp={}",resp);
         Map<String, String> result;
         try {
             result = parseKvResponse(resp);
         } catch (RuntimeException e) {
-            log.error("[OMG] queryTrade 解析响应失败 MerchantTradeNo={} resp={}", merchantTradeNo, truncate(resp, 500), e);
+            log.error("[OMG] queryTrade 解析响应失败 MerchantTradeNo={} resp={}", merchantTradeNo, resp, e);
             throw e;
         }
         try {
             verifyResponse(result, cfg, true);
         } catch (RuntimeException e) {
-            log.error("[OMG] queryTrade 验签失败 MerchantTradeNo={} resp={}", merchantTradeNo, truncate(resp, 500), e);
+            String receivedCmv = result.get("CheckMacValue");
+            String computedCmv;
+            try {
+                computedCmv = OmgCheckMacValue.generate(result, cfg.getHashKey(), cfg.getHashIv());
+            } catch (Exception ce) {
+                computedCmv = "generate-error:" + ce.getClass().getName() + ":" + ce.getMessage();
+            }
+            log.error("[OMG] queryTrade 验签失败 MerchantTradeNo={} TradeStatus={} RtnCode={} receivedCMV={} computedCMV={} hashKey={} hashIv={} resp={}",
+                    merchantTradeNo, result.get("TradeStatus"), result.get("RtnCode"),
+                    receivedCmv, computedCmv, mask(cfg.getHashKey()), mask(cfg.getHashIv()), resp, e);
             throw e;
         }
         verifyCorrelation(result, "MerchantID", cfg.getMerchantId());
@@ -260,11 +270,14 @@ public class OmgPay {
         }
     }
 
-    /** 截断响应文本用于诊断日志(null 安全)。 */
-    private static String truncate(String s, int max) {
+    /** 脱敏凭证用于日志:前2后2+长度,够排查贴错又不泄露完整值。 */
+    private static String mask(String s) {
         if (s == null) {
-            return null;
+            return "null";
+        }
+        if (s.length() <= 4) {
+            return "***(len=" + s.length() + ")";
         }
-        return s.length() <= max ? s : s.substring(0, max);
+        return s.substring(0, 2) + "***" + s.substring(s.length() - 2) + "(len=" + s.length() + ")";
     }
 }