Skip to content

Commit d0b7a52

Browse files
authored
🎨 #3587【微信支付】支持完全公钥模式,新增fullPublicKeyModel字段来控制,默认关闭,关闭时走老逻辑,开启时,只加载公钥所需相关配置,避免下载平台证书使灰度切换无法达到100%覆盖
1 parent 47051bd commit d0b7a52

File tree

2 files changed

+72
-29
lines changed

2 files changed

+72
-29
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,16 @@ static Verifier build(
9292
return null;
9393
}
9494

95+
/**
96+
* 针对完全使用公钥的场景
97+
* @param publicKeyId 公钥id
98+
* @param publicKey 公钥
99+
* @return
100+
*/
101+
static Verifier buildPublicCertVerifier(String publicKeyId, PublicKey publicKey) {
102+
return getPublicCertVerifier(publicKeyId, publicKey, null);
103+
}
104+
95105
/**
96106
* 获取证书验证器.
97107
*

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

Lines changed: 62 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,11 @@ public class WxPayConfig {
232232
*/
233233
private boolean strictlyNeedWechatPaySerial = false;
234234

235+
/**
236+
* 是否完全使用公钥模式(用以微信从平台证书到公钥的灰度切换),默认不使用
237+
*/
238+
private boolean fullPublicKeyModel = false;
239+
235240
/**
236241
* 返回所设置的微信支付接口请求地址域名.
237242
*
@@ -289,48 +294,76 @@ public CloseableHttpClient initApiV3HttpClient() throws WxPayException {
289294
if (StringUtils.isBlank(this.getApiV3Key())) {
290295
throw new WxPayException("请确保apiV3Key值已设置");
291296
}
292-
293-
// 尝试从p12证书中加载私钥和证书
294-
PrivateKey merchantPrivateKey = null;
295-
X509Certificate certificate = null;
296-
Object[] objects = this.p12ToPem();
297-
if (objects != null) {
298-
merchantPrivateKey = (PrivateKey) objects[0];
299-
certificate = (X509Certificate) objects[1];
300-
this.certSerialNo = certificate.getSerialNumber().toString(16).toUpperCase();
301-
}
302297
try {
303-
if (merchantPrivateKey == null && StringUtils.isNotBlank(this.getPrivateKeyPath())) {
304-
try (InputStream keyInputStream = this.loadConfigInputStream(this.getPrivateKeyString(), this.getPrivateKeyPath(),
305-
this.privateKeyContent, "privateKeyPath")) {
306-
merchantPrivateKey = PemUtils.loadPrivateKey(keyInputStream);
298+
PrivateKey merchantPrivateKey = null;
299+
PublicKey publicKey = null;
300+
301+
// 使用完全公钥模式时,只加载公钥相关配置,避免下载平台证书使灰度切换无法达到100%覆盖
302+
if (this.fullPublicKeyModel) {
303+
if (StringUtils.isBlank(this.getCertSerialNo())) {
304+
throw new WxPayException("使用公钥模式时,请确保certSerialNo(apiV3证书序列号)值已设置");
307305
}
308-
}
309-
if (certificate == null && StringUtils.isBlank(this.getCertSerialNo()) && StringUtils.isNotBlank(this.getPrivateCertPath())) {
310-
try (InputStream certInputStream = this.loadConfigInputStream(this.getPrivateCertString(), this.getPrivateCertPath(),
311-
this.privateCertContent, "privateCertPath")) {
312-
certificate = PemUtils.loadCertificate(certInputStream);
306+
if (StringUtils.isBlank(this.getPublicKeyId())) {
307+
throw new WxPayException("使用公钥模式时,请确保publicKeyId值已设置");
313308
}
314-
this.certSerialNo = certificate.getSerialNumber().toString(16).toUpperCase();
315-
}
316-
PublicKey publicKey = null;
317-
if (this.getPublicKeyString() != null || this.getPublicKeyPath() != null || this.publicKeyContent != null) {
309+
if (StringUtils.isBlank(this.getPublicKeyString()) && StringUtils.isBlank(this.getPublicKeyPath()) && this.getPublicKeyContent() == null) {
310+
throw new WxPayException("使用公钥模式时,请确保publicKeyString/publicKeyPath/publicKeyContent其中一项值已设置");
311+
}
312+
318313
try (InputStream pubInputStream =
319314
this.loadConfigInputStream(this.getPublicKeyString(), this.getPublicKeyPath(),
320-
this.publicKeyContent, "publicKeyPath")) {
315+
this.getPublicKeyContent(), "publicKeyPath")) {
321316
publicKey = PemUtils.loadPublicKey(pubInputStream);
322317
}
318+
} else {
319+
// 不使用完全公钥模式时,同时兼容平台证书和公钥
320+
X509Certificate certificate = null;
321+
// 尝试从p12证书中加载私钥和证书
322+
Object[] objects = this.p12ToPem();
323+
if (objects != null) {
324+
merchantPrivateKey = (PrivateKey) objects[0];
325+
certificate = (X509Certificate) objects[1];
326+
this.certSerialNo = certificate.getSerialNumber().toString(16).toUpperCase();
327+
}
328+
if (certificate == null && StringUtils.isBlank(this.getCertSerialNo()) && StringUtils.isNotBlank(this.getPrivateCertPath())) {
329+
try (InputStream certInputStream = this.loadConfigInputStream(this.getPrivateCertString(), this.getPrivateCertPath(),
330+
this.privateCertContent, "privateCertPath")) {
331+
certificate = PemUtils.loadCertificate(certInputStream);
332+
}
333+
this.certSerialNo = certificate.getSerialNumber().toString(16).toUpperCase();
334+
}
335+
if (this.getPublicKeyString() != null || this.getPublicKeyPath() != null || this.publicKeyContent != null) {
336+
if (StringUtils.isBlank(this.getPublicKeyId())) {
337+
throw new WxPayException("请确保和publicKeyId配套使用");
338+
}
339+
try (InputStream pubInputStream =
340+
this.loadConfigInputStream(this.getPublicKeyString(), this.getPublicKeyPath(),
341+
this.publicKeyContent, "publicKeyPath")) {
342+
publicKey = PemUtils.loadPublicKey(pubInputStream);
343+
}
344+
}
345+
}
346+
347+
// 加载api私钥
348+
if (merchantPrivateKey == null && StringUtils.isNotBlank(this.getPrivateKeyPath())) {
349+
try (InputStream keyInputStream = this.loadConfigInputStream(this.getPrivateKeyString(), this.getPrivateKeyPath(),
350+
this.privateKeyContent, "privateKeyPath")) {
351+
merchantPrivateKey = PemUtils.loadPrivateKey(keyInputStream);
352+
}
323353
}
324354

325355
//构造Http Proxy正向代理
326356
WxPayHttpProxy wxPayHttpProxy = getWxPayHttpProxy();
327357

328358
// 构造证书验签器
329-
Verifier certificatesVerifier = VerifierBuilder.build(
330-
this.getCertSerialNo(), this.getMchId(), this.getApiV3Key(), merchantPrivateKey, wxPayHttpProxy,
331-
this.getCertAutoUpdateTime(), this.getPayBaseUrl(),
332-
this.getPublicKeyId(), publicKey
333-
);
359+
Verifier certificatesVerifier;
360+
if (this.fullPublicKeyModel) {
361+
certificatesVerifier = VerifierBuilder.buildPublicCertVerifier(this.publicKeyId, publicKey);
362+
} else {
363+
certificatesVerifier = VerifierBuilder.build(
364+
this.getCertSerialNo(), this.getMchId(), this.getApiV3Key(), merchantPrivateKey, wxPayHttpProxy,
365+
this.getCertAutoUpdateTime(), this.getPayBaseUrl(), this.getPublicKeyId(), publicKey);
366+
}
334367

335368
WxPayV3HttpClientBuilder wxPayV3HttpClientBuilder = WxPayV3HttpClientBuilder.create()
336369
.withMerchant(mchId, certSerialNo, merchantPrivateKey)

0 commit comments

Comments
 (0)