Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RSAAutoCertificateConfig 可用于回调通知 #94

Merged
merged 1 commit into from Dec 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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