From a286bef587e8db6f96e6aeb170a186d28daccdc0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 27 Nov 2025 12:46:30 +0000 Subject: [PATCH 1/3] Initial plan From 5a6bed34c3d796dc34be7c5851e793a22e4962a3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 27 Nov 2025 12:55:35 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BB=8E=20base64=20?= =?UTF-8?q?=E5=AD=97=E7=AC=A6=E4=B8=B2=E5=8A=A0=E8=BD=BD=E5=AF=86=E9=92=A5?= =?UTF-8?q?=E6=97=B6=E7=9A=84=E5=8F=8C=E9=87=8D=E8=A7=A3=E7=A0=81=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: binarywang <1343140+binarywang@users.noreply.github.com> --- .../binarywang/wxpay/config/WxPayConfig.java | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java index efae89ce9..e04572b36 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java @@ -441,8 +441,25 @@ private InputStream loadConfigInputStream(String configString, String configPath // PEM格式直接转为字节流,让PemUtils处理 configContent = configString.getBytes(StandardCharsets.UTF_8); } else { - // 纯Base64格式,需要先解码 - configContent = Base64.getDecoder().decode(configString); + // 尝试Base64解码 + byte[] decoded = Base64.getDecoder().decode(configString); + // 检查解码后的内容是否为PEM格式(即用户传入的是base64编码的完整PEM文件) + String decodedString = new String(decoded, StandardCharsets.UTF_8); + if (decodedString.contains("-----BEGIN") && decodedString.contains("-----END")) { + // 解码后是PEM格式,使用解码后的内容 + configContent = decoded; + } else { + // 解码后不是PEM格式,可能是: + // 1. p12证书的二进制内容 - 应该返回解码后的二进制数据 + // 2. 私钥/公钥的纯base64内容(不含PEM头尾) - 应该返回原始字符串,让PemUtils处理 + // 通过certName区分:p12证书使用解码后的数据,其他情况返回原始字符串 + if ("p12证书".equals(certName)) { + configContent = decoded; + } else { + // 对于私钥/公钥/证书,返回原始字符串字节,让PemUtils处理base64解码 + configContent = configString.getBytes(StandardCharsets.UTF_8); + } + } } return new ByteArrayInputStream(configContent); } From 38e01021443af8d4e3cd7e0d62cbab97848a0846 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 27 Nov 2025 12:59:41 +0000 Subject: [PATCH 3/3] =?UTF-8?q?=E6=94=B9=E8=BF=9B=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E8=B4=A8=E9=87=8F=EF=BC=9A=E6=B7=BB=E5=8A=A0=E5=B8=B8=E9=87=8F?= =?UTF-8?q?=E3=80=81=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86=E5=92=8C=E8=BE=85?= =?UTF-8?q?=E5=8A=A9=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: binarywang <1343140+binarywang@users.noreply.github.com> --- .../binarywang/wxpay/config/WxPayConfig.java | 50 ++++++++++++------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java index e04572b36..ba62a8a50 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java @@ -55,6 +55,7 @@ public class WxPayConfig { private static final String DEFAULT_PAY_BASE_URL = "https://api.mch.weixin.qq.com"; private static final String PROBLEM_MSG = "证书文件【%s】有问题,请核实!"; private static final String NOT_FOUND_MSG = "证书文件【%s】不存在,请核实!"; + private static final String CERT_NAME_P12 = "p12证书"; /** * 微信支付接口请求地址域名部分. @@ -306,7 +307,7 @@ public SSLContext initSSLContext() throws WxPayException { } try (InputStream inputStream = this.loadConfigInputStream(this.keyString, this.getKeyPath(), - this.keyContent, "p12证书")) { + this.keyContent, CERT_NAME_P12)) { KeyStore keystore = KeyStore.getInstance("PKCS12"); char[] partnerId2charArray = this.getMchId().toCharArray(); keystore.load(inputStream, partnerId2charArray); @@ -437,28 +438,33 @@ private InputStream loadConfigInputStream(String configString, String configPath if (StringUtils.isNotEmpty(configString)) { // 判断是否为PEM格式的字符串(包含-----BEGIN和-----END标记) - if (configString.contains("-----BEGIN") && configString.contains("-----END")) { + if (isPemFormat(configString)) { // PEM格式直接转为字节流,让PemUtils处理 configContent = configString.getBytes(StandardCharsets.UTF_8); } else { // 尝试Base64解码 - byte[] decoded = Base64.getDecoder().decode(configString); - // 检查解码后的内容是否为PEM格式(即用户传入的是base64编码的完整PEM文件) - String decodedString = new String(decoded, StandardCharsets.UTF_8); - if (decodedString.contains("-----BEGIN") && decodedString.contains("-----END")) { - // 解码后是PEM格式,使用解码后的内容 - configContent = decoded; - } else { - // 解码后不是PEM格式,可能是: - // 1. p12证书的二进制内容 - 应该返回解码后的二进制数据 - // 2. 私钥/公钥的纯base64内容(不含PEM头尾) - 应该返回原始字符串,让PemUtils处理 - // 通过certName区分:p12证书使用解码后的数据,其他情况返回原始字符串 - if ("p12证书".equals(certName)) { + try { + byte[] decoded = Base64.getDecoder().decode(configString); + // 检查解码后的内容是否为PEM格式(即用户传入的是base64编码的完整PEM文件) + String decodedString = new String(decoded, StandardCharsets.UTF_8); + if (isPemFormat(decodedString)) { + // 解码后是PEM格式,使用解码后的内容 configContent = decoded; } else { - // 对于私钥/公钥/证书,返回原始字符串字节,让PemUtils处理base64解码 - configContent = configString.getBytes(StandardCharsets.UTF_8); + // 解码后不是PEM格式,可能是: + // 1. p12证书的二进制内容 - 应该返回解码后的二进制数据 + // 2. 私钥/公钥的纯base64内容(不含PEM头尾) - 应该返回原始字符串,让PemUtils处理 + // 通过certName区分:p12证书使用解码后的数据,其他情况返回原始字符串 + if (CERT_NAME_P12.equals(certName)) { + configContent = decoded; + } else { + // 对于私钥/公钥/证书,返回原始字符串字节,让PemUtils处理base64解码 + configContent = configString.getBytes(StandardCharsets.UTF_8); + } } + } catch (IllegalArgumentException e) { + // Base64解码失败,可能是格式不正确,抛出异常 + throw new WxPayException(String.format("【%s】的Base64格式不正确", certName), e); } } return new ByteArrayInputStream(configContent); @@ -471,6 +477,16 @@ private InputStream loadConfigInputStream(String configString, String configPath return this.loadConfigInputStream(configPath); } + /** + * 判断字符串是否为PEM格式(包含-----BEGIN和-----END标记) + * + * @param content 要检查的字符串 + * @return 是否为PEM格式 + */ + private boolean isPemFormat(String content) { + return content != null && content.contains("-----BEGIN") && content.contains("-----END"); + } + /** * 从配置路径 加载配置 信息(支持 classpath、本地路径、网络url) @@ -540,7 +556,7 @@ private Object[] p12ToPem() { // 分解p12证书文件 try (InputStream inputStream = this.loadConfigInputStream(this.keyString, this.getKeyPath(), - this.keyContent, "p12证书")) { + this.keyContent, CERT_NAME_P12)) { KeyStore keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(inputStream, key.toCharArray());