44
55[ 微信支付API v3] ( https://wechatpay-api.gitbook.io/wechatpay-api-v3/ ) 的[ Apache HttpClient] ( https://hc.apache.org/httpcomponents-client-ga/index.html ) 扩展,实现了请求签名的生成和应答签名的验证。
66
7- 如果你是使用Apache HttpClient的商户开发者,可以使用它构造` HttpClient ` 。得到的` HttpClient ` 在执行请求时将自动携带身份认证信息,并检查应答的微信支付签名。
7+ > [ !IMPORTANT]
8+ > 我们强烈建议你改为使用 [ WechatPay-Java] ( https://github.com/wechatpay-apiv3/wechatpay-java ) ,该SDK同样支持 Apache HttpClient 且提供了更完善的功能,本库未来只会进行必要的修复更新。
89
910## 项目状态
1011
11- 当前版本` 0.5 .0 ` 为测试版本。请商户的专业技术人员在使用时注意系统和软件的正确性和兼容性,以及带来的风险。
12+ 当前版本` 0.6 .0 ` 为测试版本。请商户的专业技术人员在使用时注意系统和软件的正确性和兼容性,以及带来的风险。
1213
1314## 升级指引
1415
15- 若你使用的版本为` 0.3 .0` ,升级前请参考[ 升级指南] ( UPGRADING.md ) 。
16+ 若你使用的版本为` <=0.5 .0` ,升级前请参考[ 升级指南] ( UPGRADING.md ) 。
1617
1718## 环境要求
1819
2728在你的` build.gradle ` 文件中加入如下的依赖
2829
2930``` groovy
30- implementation 'com.github.wechatpay-apiv3:wechatpay-apache-httpclient:0.5 .0'
31+ implementation 'com.github.wechatpay-apiv3:wechatpay-apache-httpclient:0.6 .0'
3132```
3233
3334### Maven
@@ -37,17 +38,18 @@ implementation 'com.github.wechatpay-apiv3:wechatpay-apache-httpclient:0.5.0'
3738<dependency >
3839 <groupId >com.github.wechatpay-apiv3</groupId >
3940 <artifactId >wechatpay-apache-httpclient</artifactId >
40- <version >0.5 .0</version >
41+ <version >0.6 .0</version >
4142</dependency >
4243```
4344
4445## 名词解释
4546
46- + 商户API证书,是用来证实商户身份的。证书中包含商户号、证书序列号、证书有效期等信息,由证书授权机构(Certificate Authority ,简称CA)签发,以防证书被伪造或篡改。如何获取请见[ 商户API证书] ( https://wechatpay-api.gitbook.io/wechatpay-api-v3/ren-zheng/zheng-shu#shang-hu-api-zheng-shu ) 。
47- + 商户API私钥。商户申请商户API证书时,会生成商户私钥,并保存在本地证书文件夹的文件apiclient_key.pem中。注:不要把私钥文件暴露在公共场合,如上传到Github,写在客户端代码等。
48- + 微信支付平台证书。平台证书是指由微信支付负责申请的,包含微信支付平台标识、公钥信息的证书。商户可以使用平台证书中的公钥进行应答签名的验证。获取平台证书需通过[ 获取平台证书列表] ( https://wechatpay-api.gitbook.io/wechatpay-api-v3/ren-zheng/zheng-shu#ping-tai-zheng-shu ) 接口下载。
49- + 证书序列号。每个证书都有一个由CA颁发的唯一编号,即证书序列号。如何查看证书序列号请看[ 这里] ( https://wechatpay-api.gitbook.io/wechatpay-api-v3/chang-jian-wen-ti/zheng-shu-xiang-guan#ru-he-cha-kan-zheng-shu-xu-lie-hao ) 。
50- + API v3密钥。为了保证安全性,微信支付在回调通知和平台证书下载接口中,对关键信息进行了AES-256-GCM加密。API v3密钥是加密时使用的对称密钥。商户可以在【商户平台】->【API安全】的页面设置该密钥。
47+ + ** 商户API证书** ,是用来证实商户身份的。证书中包含商户号、证书序列号、证书有效期等信息,由证书授权机构(Certificate Authority ,简称CA)签发,以防证书被伪造或篡改。如何获取请见[ 商户API证书] ( https://wechatpay-api.gitbook.io/wechatpay-api-v3/ren-zheng/zheng-shu#shang-hu-api-zheng-shu ) 。
48+ + ** 商户API私钥** 。商户申请商户API证书时,会生成商户私钥,并保存在本地证书文件夹的文件apiclient_key.pem中。注:不要把私钥文件暴露在公共场合,如上传到Github,写在客户端代码等。
49+ + ** 微信支付平台证书** 。平台证书是指由微信支付负责申请的,包含微信支付平台标识、公钥信息的证书。商户可以使用平台证书中的公钥进行应答签名的验证。获取平台证书需通过[ 获取平台证书列表] ( https://wechatpay-api.gitbook.io/wechatpay-api-v3/ren-zheng/zheng-shu#ping-tai-zheng-shu ) 接口下载。
50+ + ** 微信支付公钥** 。由微信支付生成,商户可以使用该公钥进行应答签名、回调签名的验证,详见:[ 微信支付公钥] ( https://pay.weixin.qq.com/doc/v3/merchant/4012153196 ) 。
51+ + ** 证书序列号** 。每个证书都有一个由CA颁发的唯一编号,即证书序列号。如何查看证书序列号请看[ 这里] ( https://wechatpay-api.gitbook.io/wechatpay-api-v3/chang-jian-wen-ti/zheng-shu-xiang-guan#ru-he-cha-kan-zheng-shu-xu-lie-hao ) 。
52+ + ** API v3密钥** 。为了保证安全性,微信支付在回调通知和平台证书下载接口中,对关键信息进行了AES-256-GCM加密。API v3密钥是加密时使用的对称密钥。商户可以在【商户平台】->【API安全】的页面设置该密钥。
5153
5254## 开始
5355
@@ -58,7 +60,7 @@ import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
5860// ...
5961WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder . create()
6062 .withMerchant(merchantId, merchantSerialNumber, merchantPrivateKey)
61- .withWechatPay(wechatPayCertificates );
63+ .withWechatPay(wechatpayPublicKeyId, wechatPayPublicKey );
6264// ... 接下来,你仍然可以通过builder设置各种参数,来配置你的HttpClient
6365
6466// 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签
@@ -73,7 +75,8 @@ CloseableHttpResponse response = httpClient.execute(...);
7375+ ` merchantId ` 商户号。
7476+ ` merchantSerialNumber ` 商户API证书的证书序列号。
7577+ ` merchantPrivateKey ` 商户API私钥,如何加载商户API私钥请看[ 常见问题] ( #如何加载商户私钥 ) 。
76- + ` wechatPayCertificates ` 微信支付平台证书列表。你也可以使用后面章节提到的“[ 定时更新平台证书功能] ( #定时更新平台证书功能 ) ”,而不需要关心平台证书的来龙去脉。
78+ + ` wechatpayPublicKeyId ` 微信支付公钥ID,登录商户平台可获取,详见:[ 获取微信支付公钥] ( https://pay.weixin.qq.com/doc/v3/merchant/4013053249#1.-%E8%8E%B7%E5%8F%96%E5%BE%AE%E4%BF%A1%E6%94%AF%E4%BB%98%E5%85%AC%E9%92%A5 )
79+ + ` wechatPayPublicKey ` 微信支付公钥,登录商户平台可获取,详见:[ 获取微信支付公钥] ( https://pay.weixin.qq.com/doc/v3/merchant/4013053249#1.-%E8%8E%B7%E5%8F%96%E5%BE%AE%E4%BF%A1%E6%94%AF%E4%BB%98%E5%85%AC%E9%92%A5 )
7780
7881### 示例:获取平台证书
7982
@@ -177,11 +180,14 @@ Credentials credentials = new WechatPay2Credentials(merchantId, new Signer() {
177180});
178181WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder . create()
179182 .withCredentials(credentials)
180- .withWechatPay(wechatPayCertificates );
183+ .withWechatPay(wechatpayPublicKeyId, wechatPayPublicKey );
181184```
182185
183186## 定时更新平台证书功能
184187
188+ > [ !IMPORTANT]
189+ > 新注册的商户使用「微信支付公钥」验签,不需要下载和更新平台证书。仅尚未完全迁移至「微信支付公钥」验签的旧商户才需要此能力。
190+
185191版本>=` 0.4.0 ` 可使用 CertificatesManager.getVerifier(merchantId) 得到的验签器替代默认的验签器。它会定时下载和更新商户对应的[ 微信支付平台证书] ( https://wechatpay-api.gitbook.io/wechatpay-api-v3/ren-zheng/zheng-shu#ping-tai-zheng-shu ) (默认下载间隔为UPDATE_INTERVAL_MINUTE)。
186192
187193示例代码:
@@ -197,7 +203,7 @@ certificatesManager.putMerchant(merchantId, new WechatPay2Credentials(merchantId
197203verifier = certificatesManager. getVerifier(merchantId);
198204WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder . create()
199205 .withMerchant(merchantId, merchantSerialNumber, merchantPrivateKey)
200- .withValidator(new WechatPay2Validator (verifier))
206+ .withValidator(new WechatPay2Validator (verifier));
201207// ... 接下来,你仍然可以通过builder设置各种参数,来配置你的HttpClient
202208
203209// 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新
@@ -217,13 +223,13 @@ CloseableHttpResponse response = httpClient.execute(...);
217223
218224### 加密
219225
220- 使用` RsaCryptoUtil.encryptOAEP(String, X509Certificate ) ` 进行公钥加密。示例代码如下。
226+ 使用` RsaCryptoUtil.encryptOAEP(String, PublicKey publicKey ) ` 进行公钥加密。示例代码如下。
221227
222228``` java
223229// 建议从Verifier中获得微信支付平台证书,或使用预先下载到本地的平台证书文件中
224- X509Certificate certificate = verifier. getValidCertificate ();
230+ PublicKey publicKey = verifier. getValidPublicKey ();
225231try {
226- String ciphertext = RsaCryptoUtil . encryptOAEP(text, certificate );
232+ String ciphertext = RsaCryptoUtil . encryptOAEP(text, publicKey );
227233} catch (IllegalBlockSizeException e) {
228234 e. printStackTrace();
229235}
@@ -277,15 +283,40 @@ try (FileInputStream ins1 = new FileInputStream(file)) {
2772832 . 使用` NotificationHandler ` 构造一个回调通知处理器,需设置验证器、apiV3密钥。调用` parse(request) ` 得到回调通知` notification ` 。
278284
279285示例请参考下列代码。
286+
280287``` java
281288// 构建request,传入必要参数
282- NotificationRequest request = new NotificationRequest .Builder (). withSerialNumber(wechatPaySerial)
289+ NotificationRequest request = new NotificationRequest .Builder (). withSerialNumber(wechatPaySerial)
283290 .withNonce(nonce)
284291 .withTimestamp(timestamp)
285292 .withSignature(signature)
286293 .withBody(body)
287294 .build();
288- NotificationHandler handler = new NotificationHandler (verifier, apiV3Key. getBytes(StandardCharsets . UTF_8 ));
295+
296+ // 如果已经初始化了 NotificationHandler 则直接使用,否则根据具体情况创建一个
297+
298+ // 1. 如果你使用的是微信支付公私钥,则使用公钥初始化 Verifier 以创建 NotificationHandler
299+ NotificationHandler handler = new NotificationHandler (
300+ new PublicKeyVerifier (wechatPayPublicKeyId, wechatPayPublicKey),
301+ apiV3Key. getBytes(StandardCharsets . UTF_8 )
302+ );
303+
304+ // 2. 如果你使用的事微信支付平台证书,则从 CertificatesManager 获取 Verifier 以创建 NotificationHandler
305+ NotificationHandler handler = new NotificationHandler (
306+ certificatesManager. getVerifier(merchantId),
307+ apiV3Key. getBytes(StandardCharsets . UTF_8 )
308+ );
309+
310+ // 3. 如果你正在进行微信支付平台证书到微信支付公私钥的灰度切换,希望保持切换兼容,则需要使用 MixVerifier 创建 NotificationHandler
311+ Verifier mixVerifier = new MixVerifier (
312+ new PublicKeyVerifier (wechatPayPublicKeyId, wechatPayPublicKey),
313+ certificatesManager. getVerifier(merchantId)
314+ );
315+ NotificationHandler handler = new NotificationHandler (
316+ mixVerifier,
317+ apiV3Key. getBytes(StandardCharsets . UTF_8 )
318+ );
319+
289320// 验签和解析请求体
290321Notification notification = handler. parse(request);
291322// 从notification中获取解密报文
@@ -306,11 +337,11 @@ System.out.println(notification.getDecryptData());
306337商户申请商户API证书时,会生成商户私钥,并保存在本地证书文件夹的文件` apiclient_key.pem ` 中。商户开发者可以使用方法` PemUtil.loadPrivateKey() ` 加载证书。
307338
308339``` java
309- # 示例:私钥存储在文件
340+ // 示例:私钥存储在文件
310341PrivateKey merchantPrivateKey = PemUtil . loadPrivateKey(
311342 new FileInputStream (" /path/to/apiclient_key.pem" ));
312343
313- # 示例:私钥为String 字符串
344+ // 示例:私钥为String字符串
314345PrivateKey merchantPrivateKey = PemUtil . loadPrivateKey(
315346 new ByteArrayInputStream (privateKey. getBytes(" utf-8" )));
316347```
0 commit comments