Skip to content

Commit

Permalink
RSAAutoCertificateConfig实现 NotificationConfig
Browse files Browse the repository at this point in the history
  • Loading branch information
xy-peng committed Dec 27, 2022
1 parent 09a3983 commit 778a4c7
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 22 deletions.
17 changes: 9 additions & 8 deletions README.md
Expand Up @@ -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 语言客户端开发库。

Expand Down Expand Up @@ -184,7 +184,7 @@ Config config =
同时,`RSAAutoCertificateProvider` 会启动一个后台线程,定时更新证书(目前设计为60分钟),以实现证书过期时的新老证书平滑切换。

> **Note**
> 每个商户号只能创建一个 `RSAAutoCertificateConfig`。我们建议你将配置类作为全局变量。
> 每个商户号只能创建一个 `RSAAutoCertificateConfig`。我们建议你将配置类作为全局变量。同一个商户号构造多个实例,会抛出 `IllegalStateException` 异常。
### 使用本地的微信支付平台证书

Expand All @@ -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` 验签并解密报文。

Expand All @@ -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);
Expand Down
@@ -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<Builder> {
protected HttpClient httpClient;
protected byte[] apiV3Key;
protected CertificateProvider certificateProvider;

public Builder apiV3Key(String apiV3key) {
this.apiV3Key = apiV3key.getBytes(StandardCharsets.UTF_8);
Expand All @@ -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);
}
}
}
Expand Up @@ -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;
Expand Down Expand Up @@ -92,11 +93,16 @@ public <T> 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<Builder> BuilderProvider() {
Expand Down

0 comments on commit 778a4c7

Please sign in to comment.