diff --git a/README.md b/README.md index 336c8b0a..21f0e8a3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![Maven Central](https://img.shields.io/maven-central/v/com.github.wechatpay-apiv3/wechatpay-java?versionPrefix=0.2.3) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=wechatpay-apiv3_wechatpay-java&metric=coverage)](https://sonarcloud.io/summary/new_code?id=wechatpay-apiv3_wechatpay-java) -#微信支付 APIv3 Java SDK +# 微信支付 APIv3 Java SDK [微信支付 APIv3](https://wechatpay-api.gitbook.io/wechatpay-api-v3/) 官方 Java 语言客户端开发库。 @@ -184,7 +184,7 @@ Config config = 同时,`RSAAutoCertificateProvider` 会启动一个后台线程,定时更新证书(目前设计为60分钟),以实现证书过期时的新老证书平滑切换。 > **Note** -> 每个商户号只能创建一个 `RSAAutoCertificateConfig`。我们建议你将配置类作为全局变量。 +> 每个商户号只能创建一个 `RSAAutoCertificateConfig`。我们建议你将配置类作为全局变量。同一个商户号构造多个实例,会抛出 `IllegalStateException` 异常。 ### 使用本地的微信支付平台证书 @@ -207,7 +207,7 @@ Config config = 1. 获取HTTP请求头中的 `Wechatpay-Signature` 、 `Wechatpay-Nonce` 、 `Wechatpay-Timestamp` 、 `Wechatpay-Serial` 、 `Request-ID` 、`Wechatpay-Signature-Type` 对应的值,构建 `RequestParam` 。 2. 获取 HTTP 请求体的 `JSON` 纯文本。 3. 根据解密后的通知数据数据结构,构造解密对象类 `DecryptObject` 。支付结果通知解密对象类为 [`Transaction`](service/src/main/java/com/wechat/pay/java/service/payments/model/Transaction.java),退款结果通知解密对象类为 [RefundNotification](service/src/main/java/com/wechat/pay/java/service/refund/model/RefundNotification.java)。 -4. 初始化 `AutoCertificateNotificationConfig`。微信支付平台证书由 SDK 的自动更新平台能力提供,也可以使用本地证书。 +4. 初始化 `RSAAutoCertificateConfig`。微信支付平台证书由 SDK 的自动更新平台能力提供,也可以使用本地证书。 5. 初始化 `NotificationParser`。 6. 使用请求参数 `requestParam` 和 `DecryptObject.class` ,调用 `parser.parse` 验签并解密报文。 @@ -223,16 +223,17 @@ RequestParam requestParam = new Builder() .body(requestBody) .build(); -// 初始化 NotificationConfig 使用自动更新平台证书能力,需要设置 APIv3 密钥、商户号、商户证书序列号、商户私钥。 -NotificationConfig rsaNotificationConfig = new RSAAutoCertificateNotificationConfig.Builder() - .apiV3Key(apiV3Key) +// 如果已经初始化了 RSAAutoCertificateConfig,可直接使用 +// 没有的话,则构造一个 +Config config = new RSAAutoCertificateConfig.Builder() .merchantId(merchantId) + .privateKeyFromPath(privateKeyPath) .merchantSerialNumber(merchantSerialNumber) - .autoUpdateCertWithKeyStr(privateKey) + .apiV3Key(apiV3key) .build(); // 初始化 NotificationParser -NotificationParser parser=new NotificationParser(rsaNotificationConfig); +NotificationParser parser = new NotificationParser(config); // 验签并解密报文 DecryptObject decryptObject = parser.parse(requestParam,DecryptObject.class); diff --git a/core/src/main/java/com/wechat/pay/java/core/RSAAutoCertificateConfig.java b/core/src/main/java/com/wechat/pay/java/core/RSAAutoCertificateConfig.java index bf864390..149af867 100644 --- a/core/src/main/java/com/wechat/pay/java/core/RSAAutoCertificateConfig.java +++ b/core/src/main/java/com/wechat/pay/java/core/RSAAutoCertificateConfig.java @@ -1,27 +1,80 @@ package com.wechat.pay.java.core; +import static com.wechat.pay.java.core.notification.Constant.AES_CIPHER_ALGORITHM; +import static com.wechat.pay.java.core.notification.Constant.RSA_SIGN_TYPE; import static java.util.Objects.requireNonNull; import com.wechat.pay.java.core.certificate.CertificateProvider; import com.wechat.pay.java.core.certificate.RSAAutoCertificateProvider; +import com.wechat.pay.java.core.cipher.AeadAesCipher; +import com.wechat.pay.java.core.cipher.AeadCipher; +import com.wechat.pay.java.core.cipher.RSAVerifier; +import com.wechat.pay.java.core.cipher.Verifier; import com.wechat.pay.java.core.http.HttpClient; +import com.wechat.pay.java.core.notification.NotificationConfig; import java.nio.charset.StandardCharsets; -import java.security.PrivateKey; /** 具有自动下载平台证书能力的RSA配置类 */ -public final class RSAAutoCertificateConfig extends AbstractRSAConfig { - - private RSAAutoCertificateConfig( - String merchantId, - PrivateKey privateKey, - String merchantSerialNumber, - CertificateProvider certificateProvider) { - super(merchantId, privateKey, merchantSerialNumber, certificateProvider); +public final class RSAAutoCertificateConfig extends AbstractRSAConfig + implements NotificationConfig { + + private final CertificateProvider certificateProvider; + private final AeadCipher aeadCipher; + + private RSAAutoCertificateConfig(Builder builder) { + super( + builder.merchantId, + builder.privateKey, + builder.merchantSerialNumber, + builder.certificateProvider); + this.certificateProvider = builder.certificateProvider; + this.aeadCipher = new AeadAesCipher(builder.apiV3Key); + } + + /** + * 获取签名类型 + * + * @return 签名类型 + */ + @Override + public String getSignType() { + return RSA_SIGN_TYPE; + } + + /** + * 获取认证加解密器类型 + * + * @return 认证加解密器类型 + */ + @Override + public String getCipherType() { + return AES_CIPHER_ALGORITHM; + } + + /** + * 创建验签器 + * + * @return 验签器 + */ + @Override + public Verifier createVerifier() { + return new RSAVerifier(certificateProvider); + } + + /** + * 创建认证加解密器 + * + * @return 认证加解密器 + */ + @Override + public AeadCipher createAeadCipher() { + return aeadCipher; } public static class Builder extends AbstractRSAConfigBuilder { protected HttpClient httpClient; protected byte[] apiV3Key; + protected CertificateProvider certificateProvider; public Builder apiV3Key(String apiV3key) { this.apiV3Key = apiV3key.getBytes(StandardCharsets.UTF_8); @@ -48,8 +101,10 @@ public RSAAutoCertificateConfig build() { if (httpClient != null) { providerBuilder.httpClient(httpClient); } - return new RSAAutoCertificateConfig( - merchantId, privateKey, merchantSerialNumber, providerBuilder.build()); + + certificateProvider = providerBuilder.build(); + + return new RSAAutoCertificateConfig(this); } } } diff --git a/core/src/test/java/com/wechat/pay/java/core/RSAAutoCertificateConfigTest.java b/core/src/test/java/com/wechat/pay/java/core/RSAAutoCertificateConfigTest.java index 09190e0e..04a094a4 100644 --- a/core/src/test/java/com/wechat/pay/java/core/RSAAutoCertificateConfigTest.java +++ b/core/src/test/java/com/wechat/pay/java/core/RSAAutoCertificateConfigTest.java @@ -6,9 +6,10 @@ import static com.wechat.pay.java.core.model.TestConfig.MERCHANT_PRIVATE_KEY; import static com.wechat.pay.java.core.model.TestConfig.MERCHANT_PRIVATE_KEY_PATH; import static com.wechat.pay.java.core.model.TestConfig.MERCHANT_PRIVATE_KEY_STRING; +import static com.wechat.pay.java.core.notification.Constant.AES_CIPHER_ALGORITHM; +import static com.wechat.pay.java.core.notification.Constant.RSA_SIGN_TYPE; import static java.net.HttpURLConnection.HTTP_OK; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.*; import com.wechat.pay.java.core.RSAAutoCertificateConfig.Builder; import com.wechat.pay.java.core.auth.Validator; @@ -92,11 +93,16 @@ public boolean validate(HttpHeaders responseHeaders, String body) { @ParameterizedTest @MethodSource("BuilderProvider") void testConfigWithBuilderProvider(Builder builder) { - Config config = builder.build(); + RSAAutoCertificateConfig config = builder.build(); assertNotNull(config.createValidator()); assertNotNull(config.createCredential()); assertNotNull(config.createEncryptor()); assertNotNull(config.createDecryptor()); + assertNotNull(config.createAeadCipher()); + assertNotNull(config.createVerifier()); + + assertEquals(RSA_SIGN_TYPE, config.getSignType()); + assertEquals(AES_CIPHER_ALGORITHM, config.getCipherType()); } static Stream BuilderProvider() {