修复公钥模式下自动更新证书报错问题
Co-authored-by: binarywang <1343140+binarywang@users.noreply.github.com>
This commit is contained in:
@@ -420,7 +420,13 @@ public class WxPayServiceApacheHttpImpl extends BaseWxPayServiceImpl {
|
||||
return wxPayConfig.getPublicKeyId();
|
||||
}
|
||||
|
||||
return wxPayConfig.getVerifier().getValidCertificate().getSerialNumber().toString(16).toUpperCase();
|
||||
try {
|
||||
return wxPayConfig.getVerifier().getValidCertificate().getSerialNumber().toString(16).toUpperCase();
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to get certificate serial number: {}", e.getMessage());
|
||||
// 返回空字符串而不是抛出异常,让请求继续进行,由微信服务器判断是否需要Wechatpay-Serial
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private void logRequestAndResponse(String url, String requestStr, String responseStr) {
|
||||
|
||||
@@ -398,7 +398,13 @@ public class WxPayServiceHttpComponentsImpl extends BaseWxPayServiceImpl {
|
||||
return wxPayConfig.getPublicKeyId();
|
||||
}
|
||||
|
||||
return wxPayConfig.getVerifier().getValidCertificate().getSerialNumber().toString(16).toUpperCase();
|
||||
try {
|
||||
return wxPayConfig.getVerifier().getValidCertificate().getSerialNumber().toString(16).toUpperCase();
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to get certificate serial number: {}", e.getMessage());
|
||||
// 返回空字符串而不是抛出异常,让请求继续进行,由微信服务器判断是否需要Wechatpay-Serial
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private void logRequestAndResponse(String url, String requestStr, String responseStr) {
|
||||
|
||||
@@ -109,18 +109,24 @@ public class AutoUpdateCertificatesVerifier implements Verifier {
|
||||
this.minutesInterval = minutesInterval;
|
||||
this.payBaseUrl = payBaseUrl;
|
||||
this.wxPayHttpProxy = wxPayHttpProxy;
|
||||
//构造时更新证书
|
||||
//构造时尝试更新证书,但失败时不抛出异常,避免影响公钥模式的使用
|
||||
try {
|
||||
autoUpdateCert();
|
||||
instant = Instant.now();
|
||||
} catch (IOException | GeneralSecurityException e) {
|
||||
throw new WxRuntimeException(e);
|
||||
log.warn("Auto update cert failed during initialization, will retry later, exception = {}", e.getMessage());
|
||||
// 设置instant为null,在第一次使用时会触发重新下载
|
||||
instant = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(String serialNumber, byte[] message, String signature) {
|
||||
checkAndAutoUpdateCert();
|
||||
if (verifier == null) {
|
||||
log.warn("No valid certificate available for verification");
|
||||
return false;
|
||||
}
|
||||
return verifier.verify(serialNumber, message, signature);
|
||||
}
|
||||
|
||||
@@ -220,6 +226,9 @@ public class AutoUpdateCertificatesVerifier implements Verifier {
|
||||
@Override
|
||||
public X509Certificate getValidCertificate() {
|
||||
checkAndAutoUpdateCert();
|
||||
if (verifier == null) {
|
||||
throw new WxRuntimeException("No valid certificate available, please check your configuration or use fullPublicKeyModel mode");
|
||||
}
|
||||
return verifier.getValidCertificate();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.github.binarywang.wxpay.v3.auth;
|
||||
|
||||
import com.github.binarywang.wxpay.config.WxPayHttpProxy;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
/**
|
||||
* 测试公钥模式下 AutoUpdateCertificatesVerifier 的健壮性
|
||||
*
|
||||
* @author copilot
|
||||
*/
|
||||
public class AutoUpdateCertificatesVerifierPublicKeyModeTest {
|
||||
|
||||
/**
|
||||
* 测试当证书下载失败时,构造函数不应该抛出异常
|
||||
* 这是为了支持公钥模式下的场景,在公钥模式下商户可能没有平台证书
|
||||
*/
|
||||
@Test
|
||||
public void testConstructorShouldNotThrowExceptionWhenCertDownloadFails() {
|
||||
// 使用一个无效的配置,模拟证书下载失败的场景
|
||||
String invalidMchId = "invalid_mch_id";
|
||||
String invalidApiV3Key = "invalid_api_v3_key_must_be_32_b";
|
||||
String invalidCertSerialNo = "invalid_serial_no";
|
||||
String payBaseUrl = "https://api.mch.weixin.qq.com";
|
||||
|
||||
WxPayCredentials credentials = new WxPayCredentials(
|
||||
invalidMchId,
|
||||
new PrivateKeySigner(invalidCertSerialNo, null)
|
||||
);
|
||||
|
||||
// 构造函数应该不抛出异常,即使证书下载失败
|
||||
AutoUpdateCertificatesVerifier verifier = null;
|
||||
try {
|
||||
verifier = new AutoUpdateCertificatesVerifier(
|
||||
credentials,
|
||||
invalidApiV3Key.getBytes(StandardCharsets.UTF_8),
|
||||
60,
|
||||
payBaseUrl,
|
||||
null
|
||||
);
|
||||
// 如果没有抛出异常,测试通过
|
||||
assertNotNull(verifier);
|
||||
} catch (Exception e) {
|
||||
fail("构造函数不应该抛出异常,但抛出了: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试当没有有效证书时,verify 方法应该返回 false 而不是抛出异常
|
||||
*/
|
||||
@Test
|
||||
public void testVerifyShouldReturnFalseWhenNoCertificateAvailable() {
|
||||
String invalidMchId = "invalid_mch_id";
|
||||
String invalidApiV3Key = "invalid_api_v3_key_must_be_32_b";
|
||||
String invalidCertSerialNo = "invalid_serial_no";
|
||||
String payBaseUrl = "https://api.mch.weixin.qq.com";
|
||||
|
||||
WxPayCredentials credentials = new WxPayCredentials(
|
||||
invalidMchId,
|
||||
new PrivateKeySigner(invalidCertSerialNo, null)
|
||||
);
|
||||
|
||||
AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
|
||||
credentials,
|
||||
invalidApiV3Key.getBytes(StandardCharsets.UTF_8),
|
||||
60,
|
||||
payBaseUrl,
|
||||
null
|
||||
);
|
||||
|
||||
// verify 方法应该返回 false,而不是抛出异常
|
||||
boolean result = verifier.verify("test_serial", "test_message".getBytes(), "test_signature");
|
||||
assertFalse(result, "当没有有效证书时,verify 应该返回 false");
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试当没有有效证书时,getValidCertificate 方法应该抛出有意义的异常
|
||||
*/
|
||||
@Test(expectedExceptions = me.chanjar.weixin.common.error.WxRuntimeException.class,
|
||||
expectedExceptionsMessageRegExp = ".*No valid certificate available.*")
|
||||
public void testGetValidCertificateShouldThrowMeaningfulException() {
|
||||
String invalidMchId = "invalid_mch_id";
|
||||
String invalidApiV3Key = "invalid_api_v3_key_must_be_32_b";
|
||||
String invalidCertSerialNo = "invalid_serial_no";
|
||||
String payBaseUrl = "https://api.mch.weixin.qq.com";
|
||||
|
||||
WxPayCredentials credentials = new WxPayCredentials(
|
||||
invalidMchId,
|
||||
new PrivateKeySigner(invalidCertSerialNo, null)
|
||||
);
|
||||
|
||||
AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
|
||||
credentials,
|
||||
invalidApiV3Key.getBytes(StandardCharsets.UTF_8),
|
||||
60,
|
||||
payBaseUrl,
|
||||
null
|
||||
);
|
||||
|
||||
// 应该抛出有意义的异常
|
||||
X509Certificate certificate = verifier.getValidCertificate();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user