Просмотр исходного кода

新增 ezPay 手机条码校验调试接口(Swagger 直连正式环境)

- EzPay.checkBarCodeDetail: 返回完整请求/回应/解密/真实IsExist(调试用,不兜底);IsExist 判定由正则改为 contains 更稳
- EzPayDebugController: GET /debug/ezpay/checkBarCode,写死正式凭证,Swagger 传 barCode 排查
- 注意: 含写死正式金钥,仅排查用,上线前删除本类

Co-Authored-By: Claude <noreply@anthropic.com>
qmj 5 часов назад
Родитель
Сommit
9d25391f92

+ 45 - 0
ruoyi-admin/src/main/java/com/ruoyi/app/order/EzPayDebugController.java

@@ -0,0 +1,45 @@
+package com.ruoyi.app.order;
+
+import com.ruoyi.app.utils.ezPay.EzPay;
+import com.ruoyi.app.utils.ezPay.EzPayConfig;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * ezPay 调试接口(Swagger 可调)。
+ *
+ * <p>⚠️ <b>仅排查用</b>:含写死的<b>正式环境</b>商店凭证,且直连正式 ezPay。
+ * 上线前必须删除本类,或至少加上权限注解 / 移除写死凭证,避免正式金钥泄露与被滥用。
+ *
+ * @author ruoyi
+ * @date 2026-08-03
+ */
+@RestController
+@RequestMapping("/debug/ezpay")
+public class EzPayDebugController extends BaseController {
+
+    @Autowired
+    private EzPay ezPay;
+
+    /** 正式环境商店凭证(排查用,写死)。 */
+    private static final String MERCHANT_ID = "34995723";
+    private static final String HASH_KEY = "diuFXyDzKTHmyu60IBxT9M1qgfoQW5gZ";
+    private static final String HASH_IV = "PF6B3JpTiym6zm3C";
+
+    /**
+     * 手机条码校验(直连正式环境 inv.ezpay.com.tw)。
+     *
+     * @param barCode 手机条码,如 /ABC1234(/ + 7 位大写英文/数字)
+     * @return isExist=true 条码存在于财政部平台;同时回传 ezPay 原始回应与解密内容便于排查
+     */
+    @GetMapping("/checkBarCode")
+    public AjaxResult checkBarCode(@RequestParam String barCode) throws Exception {
+        EzPayConfig cfg = new EzPayConfig(MERCHANT_ID, HASH_KEY, HASH_IV);
+        return AjaxResult.success(ezPay.checkBarCodeDetail(EzPay.BASE_PROD, cfg, barCode));
+    }
+}

+ 39 - 1
ruoyi-admin/src/main/java/com/ruoyi/app/utils/ezPay/EzPay.java

@@ -185,12 +185,50 @@ public class EzPay {
             return false;
         }
         String decrypted = EzPayEncryptUtil.decrypt(resultHex, config.getHashKey(), config.getHashIV());
-//        boolean exist = decrypted != null && decrypted.matches(".*IsExist=Y(\b|$).*");
+//        boolean exist = decrypted != null && decrypted.contains("IsExist=Y");
 //        // decrypted 形如 CellphoneBarcode=%2FABC1234&IsExist=Y
 //        log.info("[EzPay] checkBarCode decrypted={}, isExist={}", decrypted, exist);
         return true;
     }
 
+    /**
+     * 手机条码验证(详细版,调试用):返回完整请求/回应/解密/真实 IsExist,供 Swagger 排查。
+     * 与 {@link #checkBarCode} 不同:本方法返回 ezPay 真实 IsExist(Y/N),不做任何兜底。
+     */
+    public JSONObject checkBarCodeDetail(String baseUrl, EzPayConfig config, String barCode) throws Exception {
+        Map<String, Object> postData = new LinkedHashMap<>();
+        postData.put("TimeStamp", String.valueOf(System.currentTimeMillis() / 1000L));
+        postData.put("CellphoneBarcode", barCode);
+        String query = buildQuery(postData);
+        String postDataHex = EzPayEncryptUtil.encrypt(query, config.getHashKey(), config.getHashIV());
+        String checkValue = EzPayEncryptUtil.genCheckValue(postDataHex, config.getHashKey(), config.getHashIV());
+        log.info("[EzPay] checkBarCodeDetail 全量参数 >>> MerchantID={}, Version=1.0, RespondType=JSON, "
+                + "PostData明文={}, PostData密文={}, CheckValue={}, HashKey={}, HashIV={}",
+                config.getMerchantId(), postData, postDataHex, checkValue, config.getHashKey(), config.getHashIV());
+        String resp = postFormWithCheck(baseUrl + URL_CHECK_BARCODE, config.getMerchantId(), "1.0", "JSON", postDataHex, checkValue);
+        JSONObject result = new JSONObject();
+        result.put("barCode", barCode);
+        result.put("merchantId", config.getMerchantId());
+        result.put("url", baseUrl + URL_CHECK_BARCODE);
+        result.put("rawResponse", resp);
+        JSONObject json = JSON.parseObject(resp);
+        String status = json == null ? "" : json.getString("Status");
+        String decrypted = null;
+        boolean exist = false;
+        if ("SUCCESS".equals(status)) {
+            String resultHex = json.getString("Result");
+            if (resultHex != null && !resultHex.isEmpty()) {
+                decrypted = EzPayEncryptUtil.decrypt(resultHex, config.getHashKey(), config.getHashIV());
+                exist = decrypted != null && decrypted.contains("IsExist=Y");
+            }
+        }
+        result.put("status", status);
+        result.put("decrypted", decrypted);
+        result.put("isExist", exist);
+        log.info("[EzPay] checkBarCodeDetail <<< decrypted={}, isExist={}", decrypted, exist);
+        return result;
+    }
+
     /**
      * 底层调用:补充 TimeStamp → http_build_query → PostData_ 加密 → Form Post → JSON。
      *