Skip to content

Commit 00ab107

Browse files
committed
新增回调公钥验签类
1 parent a98e5df commit 00ab107

File tree

6 files changed

+230
-4
lines changed

6 files changed

+230
-4
lines changed

core/src/main/java/com/wechat/pay/java/core/cipher/AbstractVerifier.java

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ protected AbstractVerifier(String algorithmName, CertificateProvider certificate
4040
*
4141
* @param algorithmName 获取Signature对象时指定的算法,例如SHA256withRSA
4242
* @param publicKey 验签使用的微信支付平台公钥,非空
43+
* @param publicKeyId 验签使用的微信支付平台公钥id
4344
*/
4445
protected AbstractVerifier(String algorithmName, PublicKey publicKey, String publicKeyId) {
4546
this.publicKey = requireNonNull(publicKey);
@@ -48,6 +49,25 @@ protected AbstractVerifier(String algorithmName, PublicKey publicKey, String pub
4849
this.certificateProvider = null;
4950
}
5051

52+
/**
53+
* AbstractVerifier 构造函数,仅在平台证书和平台公钥灰度切换阶段使用
54+
*
55+
* @param algorithmName 获取Signature对象时指定的算法,例如SHA256withRSA
56+
* @param publicKey 验签使用的微信支付平台公钥,非空
57+
* @param publicKeyId 验签使用的微信支付平台公钥id
58+
* @param certificateProvider 验签使用的微信支付平台证书管理器,非空
59+
*/
60+
protected AbstractVerifier(
61+
String algorithmName,
62+
PublicKey publicKey,
63+
String publicKeyId,
64+
CertificateProvider certificateProvider) {
65+
this.publicKey = requireNonNull(publicKey);
66+
this.publicKeyId = publicKeyId;
67+
this.algorithmName = requireNonNull(algorithmName);
68+
this.certificateProvider = requireNonNull(certificateProvider);
69+
}
70+
5171
protected boolean verify(X509Certificate certificate, String message, String signature) {
5272
try {
5373
Signature sign = Signature.getInstance(algorithmName);
@@ -87,15 +107,19 @@ public boolean verify(String serialNumber, String message, String signature) {
87107
if (serialNumber.equals(publicKeyId)) {
88108
return verify(message, signature);
89109
}
90-
logger.error("publicKeyId[{}] and serialNumber[{}] are not equal", publicKeyId, serialNumber);
91-
return false;
110+
// 如果证书为空,则说明是传入的publicKeyId错误,如果不为空,则继续使用证书验签
111+
if (certificateProvider == null) {
112+
logger.error(
113+
"publicKeyId[{}] and serialNumber[{}] are not equal", publicKeyId, serialNumber);
114+
return false;
115+
}
92116
}
93117
// 使用证书验签
94118
requireNonNull(certificateProvider);
95119
X509Certificate certificate = certificateProvider.getCertificate(serialNumber);
96120
if (certificate == null) {
97121
logger.error(
98-
"Verify the signature and get the WechatPay certificate corresponding to "
122+
"Verify the signature and get the WechatPay certificate or publicKey corresponding to "
99123
+ "serialNumber[{}] is empty.",
100124
serialNumber);
101125
return false;

core/src/main/java/com/wechat/pay/java/core/cipher/RSAVerifier.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,8 @@ public RSAVerifier(CertificateProvider provider) {
1515
public RSAVerifier(PublicKey publicKey, String publicKeyId) {
1616
super(SHA256WITHRSA, publicKey, publicKeyId);
1717
}
18+
19+
public RSAVerifier(PublicKey publicKey, String publicKeyId, CertificateProvider provider) {
20+
super(SHA256WITHRSA, publicKey, publicKeyId, provider);
21+
}
1822
}

core/src/main/java/com/wechat/pay/java/core/notification/AbstractNotificationConfig.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@
44
import com.wechat.pay.java.core.cipher.AeadCipher;
55
import com.wechat.pay.java.core.cipher.RSAVerifier;
66
import com.wechat.pay.java.core.cipher.Verifier;
7+
import java.security.PublicKey;
78

89
public abstract class AbstractNotificationConfig implements NotificationConfig {
910

1011
public final String signType;
1112
private final String cipherAlgorithm;
1213
private final CertificateProvider certificateProvider;
1314
private final AeadCipher aeadCipher;
15+
private final PublicKey publicKey;
16+
private final String publicKeyId;
1417

1518
protected AbstractNotificationConfig(
1619
String signType,
@@ -21,6 +24,37 @@ protected AbstractNotificationConfig(
2124
this.cipherAlgorithm = cipherAlgorithm;
2225
this.certificateProvider = certificateProvider;
2326
this.aeadCipher = aeadCipher;
27+
this.publicKey = null;
28+
this.publicKeyId = null;
29+
}
30+
31+
protected AbstractNotificationConfig(
32+
String signType,
33+
String cipherAlgorithm,
34+
PublicKey publicKey,
35+
String publicKeyId,
36+
AeadCipher aeadCipher) {
37+
this.signType = signType;
38+
this.cipherAlgorithm = cipherAlgorithm;
39+
this.publicKey = publicKey;
40+
this.publicKeyId = publicKeyId;
41+
this.aeadCipher = aeadCipher;
42+
this.certificateProvider = null;
43+
}
44+
45+
protected AbstractNotificationConfig(
46+
String signType,
47+
String cipherAlgorithm,
48+
CertificateProvider certificateProvider,
49+
PublicKey publicKey,
50+
String publicKeyId,
51+
AeadCipher aeadCipher) {
52+
this.signType = signType;
53+
this.cipherAlgorithm = cipherAlgorithm;
54+
this.publicKey = publicKey;
55+
this.publicKeyId = publicKeyId;
56+
this.aeadCipher = aeadCipher;
57+
this.certificateProvider = certificateProvider;
2458
}
2559

2660
@Override
@@ -35,6 +69,12 @@ public String getCipherType() {
3569

3670
@Override
3771
public Verifier createVerifier() {
72+
if (publicKey != null && certificateProvider != null) {
73+
return new RSAVerifier(publicKey, publicKeyId, certificateProvider);
74+
}
75+
if (publicKey != null) {
76+
return new RSAVerifier(publicKey, publicKeyId);
77+
}
3878
return new RSAVerifier(certificateProvider);
3979
}
4080

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package com.wechat.pay.java.core.notification;
2+
3+
import static com.wechat.pay.java.core.notification.Constant.AES_CIPHER_ALGORITHM;
4+
import static com.wechat.pay.java.core.notification.Constant.RSA_SIGN_TYPE;
5+
import static java.util.Objects.requireNonNull;
6+
7+
import com.wechat.pay.java.core.AbstractRSAConfigBuilder;
8+
import com.wechat.pay.java.core.certificate.CertificateProvider;
9+
import com.wechat.pay.java.core.certificate.RSAAutoCertificateProvider;
10+
import com.wechat.pay.java.core.cipher.AeadAesCipher;
11+
import com.wechat.pay.java.core.cipher.AeadCipher;
12+
import com.wechat.pay.java.core.http.HttpClient;
13+
import com.wechat.pay.java.core.util.PemUtil;
14+
import java.nio.charset.StandardCharsets;
15+
import java.security.PublicKey;
16+
17+
/** 通知回调配置类 该类仅在商户由平台证书切换为平台公钥的灰度阶段使用,灰度完成后请切换为RSAPublicKeyNotificationConfig */
18+
public final class RSACombinedNotificationConfig extends AbstractNotificationConfig {
19+
20+
private RSACombinedNotificationConfig(
21+
CertificateProvider certificateProvider,
22+
PublicKey publicKey,
23+
String publicKeyId,
24+
AeadCipher aeadAesCipher) {
25+
super(
26+
RSA_SIGN_TYPE,
27+
AES_CIPHER_ALGORITHM,
28+
certificateProvider,
29+
publicKey,
30+
publicKeyId,
31+
aeadAesCipher);
32+
}
33+
34+
public static class Builder extends AbstractRSAConfigBuilder<Builder> {
35+
protected HttpClient httpClient;
36+
protected byte[] apiV3Key;
37+
38+
private PublicKey publicKey;
39+
private String publicKeyId;
40+
41+
public Builder apiV3Key(String apiV3Key) {
42+
this.apiV3Key = apiV3Key.getBytes(StandardCharsets.UTF_8);
43+
return this;
44+
}
45+
46+
public Builder httpClient(HttpClient httpClient) {
47+
this.httpClient = httpClient;
48+
return this;
49+
}
50+
51+
public Builder publicKey(String publicKey) {
52+
this.publicKey = PemUtil.loadPublicKeyFromString(publicKey);
53+
return this;
54+
}
55+
56+
public Builder publicKey(PublicKey publicKey) {
57+
this.publicKey = publicKey;
58+
return this;
59+
}
60+
61+
public Builder publicFromPath(String publicKeyPath) {
62+
this.publicKey = PemUtil.loadPublicKeyFromPath(publicKeyPath);
63+
return this;
64+
}
65+
66+
public Builder publicKeyId(String publicKeyId) {
67+
this.publicKeyId = publicKeyId;
68+
return this;
69+
}
70+
71+
@Override
72+
protected Builder self() {
73+
return this;
74+
}
75+
76+
public RSACombinedNotificationConfig build() {
77+
78+
RSAAutoCertificateProvider.Builder builder =
79+
new RSAAutoCertificateProvider.Builder()
80+
.apiV3Key(requireNonNull(apiV3Key))
81+
.privateKey(requireNonNull(privateKey))
82+
.merchantId(requireNonNull(merchantId))
83+
.merchantSerialNumber(requireNonNull(merchantSerialNumber));
84+
if (httpClient != null) {
85+
builder.httpClient(httpClient);
86+
}
87+
return new RSACombinedNotificationConfig(
88+
builder.build(),
89+
requireNonNull(publicKey),
90+
requireNonNull(publicKeyId),
91+
new AeadAesCipher(requireNonNull(apiV3Key)));
92+
}
93+
}
94+
}

core/src/main/java/com/wechat/pay/java/core/notification/RSANotificationConfig.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@
1515
import java.util.Arrays;
1616
import java.util.List;
1717

18-
/** 签名类型为RSA的通知配置参数 */
18+
/**
19+
* 通知回调配置类
20+
*
21+
* @deprecated 请使用 RSAAutoCertificateConfig,开发者应尽快迁移,我们将在未来某个时间移除这段废弃的代码。
22+
*/
1923
public final class RSANotificationConfig extends AbstractNotificationConfig {
2024

2125
private RSANotificationConfig(CertificateProvider certificateProvider, AeadCipher aeadCipher) {
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.wechat.pay.java.core.notification;
2+
3+
import static com.wechat.pay.java.core.notification.Constant.AES_CIPHER_ALGORITHM;
4+
import static com.wechat.pay.java.core.notification.Constant.RSA_SIGN_TYPE;
5+
import static java.util.Objects.requireNonNull;
6+
7+
import com.wechat.pay.java.core.cipher.AeadAesCipher;
8+
import com.wechat.pay.java.core.cipher.AeadCipher;
9+
import com.wechat.pay.java.core.util.PemUtil;
10+
import java.nio.charset.StandardCharsets;
11+
import java.security.PublicKey;
12+
13+
/** 签名类型为RSA的通知配置参数 */
14+
public final class RSAPublicKeyNotificationConfig extends AbstractNotificationConfig {
15+
16+
private RSAPublicKeyNotificationConfig(
17+
PublicKey publicKey, String publicKeyId, AeadCipher aeadCipher) {
18+
super(RSA_SIGN_TYPE, AES_CIPHER_ALGORITHM, publicKey, publicKeyId, aeadCipher);
19+
}
20+
21+
public static class Builder {
22+
private byte[] apiV3Key;
23+
24+
private PublicKey publicKey;
25+
private String publicKeyId;
26+
27+
public Builder publicKey(String publicKey) {
28+
this.publicKey = PemUtil.loadPublicKeyFromString(publicKey);
29+
return this;
30+
}
31+
32+
public Builder publicKey(PublicKey publicKey) {
33+
this.publicKey = publicKey;
34+
return this;
35+
}
36+
37+
public Builder publicFromPath(String publicKeyPath) {
38+
this.publicKey = PemUtil.loadPublicKeyFromPath(publicKeyPath);
39+
return this;
40+
}
41+
42+
public Builder apiV3Key(String apiV3Key) {
43+
this.apiV3Key = apiV3Key.getBytes(StandardCharsets.UTF_8);
44+
return this;
45+
}
46+
47+
public Builder publicKeyId(String publicKeyId) {
48+
this.publicKeyId = publicKeyId;
49+
return this;
50+
}
51+
52+
public RSAPublicKeyNotificationConfig build() {
53+
requireNonNull(publicKey);
54+
requireNonNull(publicKeyId);
55+
requireNonNull(apiV3Key);
56+
return new RSAPublicKeyNotificationConfig(
57+
publicKey, requireNonNull(publicKeyId), new AeadAesCipher(requireNonNull(apiV3Key)));
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)