Skip to content

Commit e57b7e1

Browse files
authored
🎨 #3765 【微信支付】修复从 base64 字符串加载私钥时的双重解码问题
1 parent 833f60c commit e57b7e1

File tree

1 file changed

+38
-5
lines changed
  • weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config

1 file changed

+38
-5
lines changed

weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public class WxPayConfig {
5555
private static final String DEFAULT_PAY_BASE_URL = "https://api.mch.weixin.qq.com";
5656
private static final String PROBLEM_MSG = "证书文件【%s】有问题,请核实!";
5757
private static final String NOT_FOUND_MSG = "证书文件【%s】不存在,请核实!";
58+
private static final String CERT_NAME_P12 = "p12证书";
5859

5960
/**
6061
* 微信支付接口请求地址域名部分.
@@ -306,7 +307,7 @@ public SSLContext initSSLContext() throws WxPayException {
306307
}
307308

308309
try (InputStream inputStream = this.loadConfigInputStream(this.keyString, this.getKeyPath(),
309-
this.keyContent, "p12证书")) {
310+
this.keyContent, CERT_NAME_P12)) {
310311
KeyStore keystore = KeyStore.getInstance("PKCS12");
311312
char[] partnerId2charArray = this.getMchId().toCharArray();
312313
keystore.load(inputStream, partnerId2charArray);
@@ -437,12 +438,34 @@ private InputStream loadConfigInputStream(String configString, String configPath
437438

438439
if (StringUtils.isNotEmpty(configString)) {
439440
// 判断是否为PEM格式的字符串(包含-----BEGIN和-----END标记)
440-
if (configString.contains("-----BEGIN") && configString.contains("-----END")) {
441+
if (isPemFormat(configString)) {
441442
// PEM格式直接转为字节流,让PemUtils处理
442443
configContent = configString.getBytes(StandardCharsets.UTF_8);
443444
} else {
444-
// 纯Base64格式,需要先解码
445-
configContent = Base64.getDecoder().decode(configString);
445+
// 尝试Base64解码
446+
try {
447+
byte[] decoded = Base64.getDecoder().decode(configString);
448+
// 检查解码后的内容是否为PEM格式(即用户传入的是base64编码的完整PEM文件)
449+
String decodedString = new String(decoded, StandardCharsets.UTF_8);
450+
if (isPemFormat(decodedString)) {
451+
// 解码后是PEM格式,使用解码后的内容
452+
configContent = decoded;
453+
} else {
454+
// 解码后不是PEM格式,可能是:
455+
// 1. p12证书的二进制内容 - 应该返回解码后的二进制数据
456+
// 2. 私钥/公钥的纯base64内容(不含PEM头尾) - 应该返回原始字符串,让PemUtils处理
457+
// 通过certName区分:p12证书使用解码后的数据,其他情况返回原始字符串
458+
if (CERT_NAME_P12.equals(certName)) {
459+
configContent = decoded;
460+
} else {
461+
// 对于私钥/公钥/证书,返回原始字符串字节,让PemUtils处理base64解码
462+
configContent = configString.getBytes(StandardCharsets.UTF_8);
463+
}
464+
}
465+
} catch (IllegalArgumentException e) {
466+
// Base64解码失败,可能是格式不正确,抛出异常
467+
throw new WxPayException(String.format("【%s】的Base64格式不正确", certName), e);
468+
}
446469
}
447470
return new ByteArrayInputStream(configContent);
448471
}
@@ -454,6 +477,16 @@ private InputStream loadConfigInputStream(String configString, String configPath
454477
return this.loadConfigInputStream(configPath);
455478
}
456479

480+
/**
481+
* 判断字符串是否为PEM格式(包含-----BEGIN和-----END标记)
482+
*
483+
* @param content 要检查的字符串
484+
* @return 是否为PEM格式
485+
*/
486+
private boolean isPemFormat(String content) {
487+
return content != null && content.contains("-----BEGIN") && content.contains("-----END");
488+
}
489+
457490

458491
/**
459492
* 从配置路径 加载配置 信息(支持 classpath、本地路径、网络url)
@@ -523,7 +556,7 @@ private Object[] p12ToPem() {
523556

524557
// 分解p12证书文件
525558
try (InputStream inputStream = this.loadConfigInputStream(this.keyString, this.getKeyPath(),
526-
this.keyContent, "p12证书")) {
559+
this.keyContent, CERT_NAME_P12)) {
527560
KeyStore keyStore = KeyStore.getInstance("PKCS12");
528561
keyStore.load(inputStream, key.toCharArray());
529562

0 commit comments

Comments
 (0)