收藏
回答

微信支付,根据商户订单号退款接口,报错{"code":"SIGN_ERROR","message"?

public static void main(String[] args) {
    try {
        Map<String, Object> refundParams = new HashMap<>();
        refundParams.put("out_trade_no", "ET1000000722");
        refundParams.put("out_refund_no", "ET10000007223");
        Map<String, Integer> amount = new HashMap<>();
        amount.put("total", 1);
        amount.put("refund", 1);
        refundParams.put("amount", amount);

        String response = sendRefundRequest(refundParams);
        System.out.println("退款接口返回结果:" + response);

    } catch (Exception e) {
        e.printStackTrace();
    }
}

private static PrivateKey loadPrivateKey(String certPath) throws Exception {
    try (InputStream inputStream = new FileInputStream(certPath)) {
        return PemUtil.loadPrivateKey(inputStream);
    }
}

public static String sendRefundRequest(Map<String, Object> params) throws Exception {
    Gson gson = new Gson();
    String requestBody = gson.toJson(params);

    PrivateKey privateKey = loadPrivateKey(CERT_PATH);

    String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
    String nonceStr = generateNonceStr();

    String signature = generateSignature(timestamp, nonceStr, API_V3_KEY, privateKey, params);

    String authorization = String.format("WECHATPAY2-SHA256-RSA2048 mchid=\"%s\",nonce_str=\"%s\",timestamp=\"%s\",signature=\"%s\"",
            MCH_ID, nonceStr, timestamp, signature);

    CloseableHttpClient httpClient = getHttpClientWithCert(CERT_PATH);

    HttpPost httpPost = new HttpPost(REFUND_URL);
    httpPost.addHeader("Authorization", authorization);
    httpPost.addHeader("Content-Type", "application/json");
    httpPost.addHeader("Accept", "application/json");
    httpPost.addHeader("User-Agent", "WeChatJavaClient/1.0");

    httpPost.setEntity(new StringEntity(requestBody, "UTF-8"));

    CloseableHttpResponse response = httpClient.execute(httpPost);
    HttpEntity responseEntity = response.getEntity();
    String responseBody = EntityUtils.toString(responseEntity, "UTF-8");

    response.close();
    httpClient.close();

    return responseBody;
}

private static String generateSignature(String timestamp, String nonceStr, String apiV3Key, PrivateKey privateKey, Map<String, Object> params) throws Exception {
    // 如果 params 为空,则 body 为 ""
    String body = params == null || params.isEmpty() ? "" : sha256(new Gson().toJson(params));

    // 拼接签名字符串
    String signStr = String.format("POST\n%s\n%s\n%s\n%s\n", REFUND_URL, timestamp, nonceStr, body);

    // 使用 RSA 私钥对签名字符串进行签名
    java.security.Signature signature = java.security.Signature.getInstance("SHA256withRSA");
    signature.initSign(privateKey);
    signature.update(signStr.getBytes("UTF-8"));
    return Base64.getEncoder().encodeToString(signature.sign());
}

private static String sha256(String input) throws Exception {
    java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-256");
    byte[] hash = md.digest(input.getBytes("UTF-8"));
    return bytesToHex(hash);
}

private static String bytesToHex(byte[] bytes) {
    StringBuilder sb = new StringBuilder();
    for (byte b : bytes) {
        sb.append(String.format("%02x", b));
    }
    return sb.toString();
}

private static String generateNonceStr() {
    return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
}

private static CloseableHttpClient getHttpClientWithCert(String certPath) throws Exception {
    PrivateKey privateKey = loadPrivateKey(certPath);

    KeyManager[] keyManagers = new KeyManager[]{new CustomX509KeyManager(privateKey)};

    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(keyManagers, null, null);

    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
    return HttpClients.custom().setSSLSocketFactory(sslsf).build();
}

static class CustomX509KeyManager implements X509KeyManager {
    private final PrivateKey privateKey;

    public CustomX509KeyManager(PrivateKey privateKey) {
        this.privateKey = privateKey;
    }

    @Override
    public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
        return "dummyAlias"; // 返回一个虚拟别名
    }

    @Override
    public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
        return null; // 服务器端不需要实现
    }

    @Override
    public X509Certificate[] getCertificateChain(String alias) {
        return null; // 这里可以返回证书链(如果需要)
    }

    @Override
    public String[] getClientAliases(String keyType, Principal[] issuers) {
        return new String[]{"dummyAlias"}; // 返回虚拟别名列表
    }

    @Override
    public String[] getServerAliases(String keyType, Principal[] issuers) {
        return null; // 服务器端不需要实现
    }

    @Override
    public PrivateKey getPrivateKey(String alias) {
        return privateKey; // 返回私钥
    }
}


回答关注问题邀请回答
收藏

1 个回答

登录 后发表内容