mirror of
https://github.com/dromara/payment-spring-boot.git
synced 2026-03-14 05:43:46 +08:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46b7047674 | ||
|
|
095a1e4a4a | ||
|
|
8470286af6 | ||
|
|
e20e19e66a | ||
|
|
c43a91a2de | ||
|
|
dedde9515d | ||
|
|
f0e2495bfd | ||
|
|
b4ff87b80b | ||
|
|
62eaf468fb | ||
|
|
a4fa017cec | ||
|
|
20f80c16db | ||
|
|
7be5971ae3 | ||
|
|
7388a75455 | ||
|
|
6d321273be | ||
|
|
f2f544be9d | ||
|
|
7f2591b3c4 | ||
|
|
8bf83662fb | ||
|
|
9ceeabd9e3 |
35
README.md
35
README.md
@@ -45,7 +45,7 @@ Starter,支持微信优惠券,代金券、商家券、智慧商圈、商家
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.felord</groupId>
|
<groupId>cn.felord</groupId>
|
||||||
<artifactId>payment-spring-boot-starter</artifactId>
|
<artifactId>payment-spring-boot-starter</artifactId>
|
||||||
<version>1.0.20.RELEASE</version>
|
<version>1.0.21.RELEASE</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -55,24 +55,47 @@ Starter,支持微信优惠券,代金券、商家券、智慧商圈、商家
|
|||||||
|
|
||||||
## 文档地址
|
## 文档地址
|
||||||
|
|
||||||
- [payment-spring-boot GitHub文档](https://dromara.github.io/payment-spring-boot)
|
- ~~[payment-spring-boot GitHub文档](https://dromara.github.io/payment-spring-boot) (暂时不可用)~~
|
||||||
|
|
||||||
## API清单
|
## API清单
|
||||||
|
|
||||||
目前已经实现绝大部分微信支付直连商户和服务商的接口,具体的API明细可查看[API清单](https://dromara.github.io/payment-spring-boot/#/wechat_v3_api)
|
目前已经实现绝大部分微信支付直连商户和服务商的接口,具体的API明细可查看[API清单(暂时不可用)](https://dromara.github.io/payment-spring-boot/#/wechat_v3_api)
|
||||||
> 随着版本迭代功能会增加,也可通过API注册表类`WechatPayV3Type`进行API接口检索。
|
> 随着版本迭代功能会增加,也可通过API注册表类`WechatPayV3Type`进行API接口检索。
|
||||||
|
|
||||||
## CHANGELOG
|
## CHANGELOG
|
||||||
|
|
||||||
更新日志[CHANGELOG](https://dromara.github.io/payment-spring-boot/#/changelog)
|
~~更新日志[CHANGELOG](https://dromara.github.io/payment-spring-boot/#/changelog) (暂时不可用)~~
|
||||||
|
|
||||||
## 使用入门
|
## 使用入门
|
||||||
|
|
||||||
### 集成配置
|
### 集成配置
|
||||||
|
|
||||||
关于集成配置请详细阅读[payment-spring-boot GitHub文档](https://dromara.github.io/payment-spring-boot)
|
~~关于集成配置请详细阅读[payment-spring-boot GitHub文档](https://dromara.github.io/payment-spring-boot)
|
||||||
中[快速接入](https://dromara.github.io/payment-spring-boot/#/quick_start)章节
|
中[快速接入](https://dromara.github.io/payment-spring-boot/#/quick_start)章节 (暂时不可用)~~
|
||||||
|
|
||||||
|
[关于微信支付公钥](https://pay.weixin.qq.com/doc/v3/merchant/4012153196)
|
||||||
|
微信官方推出了微信支付公钥产品以替代原来的微信平台证书,我们对此进行了适配
|
||||||
|
相关配置如下
|
||||||
|
```yaml
|
||||||
|
wechat:
|
||||||
|
pay:
|
||||||
|
v3:
|
||||||
|
# 租户id
|
||||||
|
<tentantId>:
|
||||||
|
# 是否使用微信支付公钥验签 默认false
|
||||||
|
enable-wechat-pay-public: true
|
||||||
|
# 微信支付公钥id
|
||||||
|
wechat-pay-public-key-id: PUB_KEY_ID_1111213
|
||||||
|
# 微信支付公钥路径
|
||||||
|
wechat-pay-public-key-path: 'pub_key.pem'
|
||||||
|
|
||||||
|
wechat-pay-public-key-absolute-path: ''
|
||||||
|
# 是否启用签名验签方法切换 默认false
|
||||||
|
switch-verify-sign-method: true
|
||||||
|
```
|
||||||
|
- 对于旧版本商户,若不使用微信支付公钥,则不需要配置上述对应参数,则默认使用微信平台证书验签。
|
||||||
|
- 对于新进件的商户,微信官方默认启用支付公钥,需要配置上述参数。其中 `switch-verify-sign-method` 参数不需要配置
|
||||||
|
- 若旧版版商户使用微信支付公钥,则需要配置上述参数,并启用 `switch-verify-sign-method : true` [原理参考](https://pay.weixin.qq.com/doc/v3/merchant/4012154180)。<font color=red>当完成从平台证书切换到微信支付公钥后,请务必将`switch-verify-sign-method`参数设置为false 或删除该字段</font>
|
||||||
### 调用示例
|
### 调用示例
|
||||||
|
|
||||||
#### 开启支付
|
#### 开启支付
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.felord</groupId>
|
<groupId>cn.felord</groupId>
|
||||||
<artifactId>payment-spring-boot-starter</artifactId>
|
<artifactId>payment-spring-boot-starter</artifactId>
|
||||||
<version>1.0.20.RELEASE</version>
|
<version>1.0.21.RELEASE</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
## 采用技术
|
## 采用技术
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
## 1.0.21.RELEASE
|
||||||
|
### 微信支付
|
||||||
|
|
||||||
|
- enhance: 增加了通过微信公钥对微信支付相关接口的响应内容或微信回调通知的参数进行验签的支持。
|
||||||
|
- 微信配置项增加了:```enable-wechat-pay-public: 是否启用微信支付公钥验签、 wechat-pay-public-key-id: 微信支付公钥的ID、 wechat-pay-public-key-path:微信支付公钥的路径、wechat-pay-public-key-absolute-path: 微信支付公钥的绝对路径、 switch-verify-sign-method: 是否启用从平台证书切换到微信支公钥```
|
||||||
|
- `enable-wechat-pay-public` 与 `wechat-pay-public-key-id ` 、`wechat-pay-public-key-path或wechat-pay-public-key-absolute-path`<font color=red>同时正确配置</font>,才会启用微信支付公钥验签,否则默认使用平台证书进行验签。
|
||||||
|
-
|
||||||
|
- 如果需要[从平台证书切换成微信支付公钥](https://pay.weixin.qq.com/doc/v3/merchant/4012154180#5.-%E6%B2%A1%E6%9C%89%E4%BD%BF%E7%94%A8%E5%BE%AE%E4%BF%A1%E6%94%AF%E4%BB%98SDK%E7%9A%84%E5%95%86%E6%88%B7%E5%A6%82%E4%BD%95%E5%B0%86%E5%B9%B3%E5%8F%B0%E8%AF%81%E4%B9%A6%E5%88%87%E6%8D%A2%E6%88%90%E5%BE%AE%E4%BF%A1%E6%94%AF%E4%BB%98%E5%85%AC%E9%92%A5),请启用`switch-verify-sign-method`参数
|
||||||
|
- enhance: 增加了微信支付V3版本的付款码支付``codePay``与撤销API``reverse``(仅支持普通商户模式,服务商模式暂不支持)
|
||||||
|
- factor: 升级了spring-boot-parent版本从 2.7.7 到2.7.18
|
||||||
|
- factor: 升级了Alipay SDK版本从4.31.7.ALL到4.40.251.ALL
|
||||||
## 1.0.18.RELEASE
|
## 1.0.18.RELEASE
|
||||||
### 微信支付
|
### 微信支付
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.felord</groupId>
|
<groupId>cn.felord</groupId>
|
||||||
<artifactId>payment-spring-boot-starter</artifactId>
|
<artifactId>payment-spring-boot-starter</artifactId>
|
||||||
<version>1.0.20.RELEASE</version>
|
<version>1.0.21.RELEASE</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
> 基于 **Spring Boot 2.x**
|
> 基于 **Spring Boot 2.x**
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
```xml
|
```xml
|
||||||
<properties>
|
<properties>
|
||||||
<!-- 修改为你对应的Spring Boot版本号 -->
|
<!-- 修改为你对应的Spring Boot版本号 -->
|
||||||
<spring-boot.version>2.4.0</spring-boot.version>
|
<spring-boot.version>2.7.18</spring-boot.version>
|
||||||
</properties>
|
</properties>
|
||||||
```
|
```
|
||||||
然后安装使用
|
然后安装使用
|
||||||
@@ -86,6 +86,15 @@ wechat:
|
|||||||
mch-id: 1603337223
|
mch-id: 1603337223
|
||||||
domain: https://felord.cn/miniapp
|
domain: https://felord.cn/miniapp
|
||||||
cert-path: miniapp/apiclient_cert.p12
|
cert-path: miniapp/apiclient_cert.p12
|
||||||
|
# 是否启用微信支付公钥
|
||||||
|
enable-wechat-pay-public: true
|
||||||
|
#微信公钥ID
|
||||||
|
wechat-pay-public-key-id: PUB_KEY_ID_0116278111111115222222501
|
||||||
|
#微信公钥
|
||||||
|
wechat-pay-public-key-path: pub_key.pem
|
||||||
|
wechat-pay-public-key-absolute-path: D:\\felord\\wechat\\cert\\pub_key.pem
|
||||||
|
#是否启用从平台证书切换成微信支付公钥 不填默认为false,
|
||||||
|
switch-verify-sign-method: true
|
||||||
```
|
```
|
||||||
|
|
||||||
> ❗注意:在一套系统中需要开发者保证`tentanID`唯一。
|
> ❗注意:在一套系统中需要开发者保证`tentanID`唯一。
|
||||||
|
|||||||
@@ -22,11 +22,11 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>cn.felord</groupId>
|
<groupId>cn.felord</groupId>
|
||||||
<artifactId>payment-spring-boot</artifactId>
|
<artifactId>payment-spring-boot</artifactId>
|
||||||
<version>1.0.20.RELEASE</version>
|
<version>1.0.21.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>payment-spring-boot-autoconfigure</artifactId>
|
<artifactId>payment-spring-boot-autoconfigure</artifactId>
|
||||||
<version>1.0.20.RELEASE</version>
|
<version>1.0.21.RELEASE</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|||||||
@@ -17,15 +17,23 @@
|
|||||||
|
|
||||||
package cn.felord.payment.wechat;
|
package cn.felord.payment.wechat;
|
||||||
|
|
||||||
import cn.felord.payment.wechat.v3.KeyPairFactory;
|
import cn.felord.payment.PayException;
|
||||||
import cn.felord.payment.wechat.v3.WechatMetaBean;
|
import cn.felord.payment.wechat.v3.*;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.bouncycastle.util.io.pem.PemObject;
|
||||||
|
import org.bouncycastle.util.io.pem.PemReader;
|
||||||
import org.springframework.core.io.FileSystemResource;
|
import org.springframework.core.io.FileSystemResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.core.io.ResourceLoader;
|
import org.springframework.core.io.ResourceLoader;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.util.ResourceUtils;
|
import org.springframework.util.ResourceUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.security.KeyFactory;
|
||||||
|
import java.security.interfaces.RSAPublicKey;
|
||||||
|
import java.security.spec.X509EncodedKeySpec;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -62,6 +70,7 @@ public class InMemoryWechatTenantService implements WechatTenantService {
|
|||||||
WechatMetaBean wechatMetaBean = keyPairFactory.initWechatMetaBean(resource, mchId);
|
WechatMetaBean wechatMetaBean = keyPairFactory.initWechatMetaBean(resource, mchId);
|
||||||
wechatMetaBean.setV3(v3);
|
wechatMetaBean.setV3(v3);
|
||||||
wechatMetaBean.setTenantId(tenantId);
|
wechatMetaBean.setTenantId(tenantId);
|
||||||
|
SignatureProvider.addWeChatPublicKey(initWeChatPublicKeyInfo(wechatMetaBean));
|
||||||
return wechatMetaBean;
|
return wechatMetaBean;
|
||||||
})
|
})
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
@@ -69,4 +78,29 @@ public class InMemoryWechatTenantService implements WechatTenantService {
|
|||||||
}
|
}
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WeChatPublicKeyInfo initWeChatPublicKeyInfo(WechatMetaBean meta) {
|
||||||
|
boolean enablePublicKey=StringUtils.hasLength(meta.getV3().getWechatPayPublicKeyId()) &&
|
||||||
|
(StringUtils.hasLength(meta.getV3().getWechatPayPublicKeyPath())||StringUtils.hasLength(meta.getV3().getWechatPayPublicKeyAbsolutePath()));
|
||||||
|
if (!enablePublicKey) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String certPath=meta.getV3().getWechatPayPublicKeyPath();
|
||||||
|
String certAbsolutePath = meta.getV3().getWechatPayPublicKeyAbsolutePath();
|
||||||
|
Resource resource =
|
||||||
|
StringUtils.hasLength(certAbsolutePath) ? new FileSystemResource(certAbsolutePath) :
|
||||||
|
resourceLoader.getResource(!StringUtils.hasLength(certPath) ? "classpath:wechat/pub_key.pem" :
|
||||||
|
certPath.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX) ? certPath : ResourceUtils.CLASSPATH_URL_PREFIX + certPath);
|
||||||
|
PemReader pemReader = new PemReader(new InputStreamReader(resource.getInputStream()));
|
||||||
|
PemObject pemObject = pemReader.readPemObject();
|
||||||
|
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(pemObject.getContent());
|
||||||
|
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||||
|
RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
|
||||||
|
// 生成公钥
|
||||||
|
return new WeChatPublicKeyInfo(publicKey, meta.getV3().getWechatPayPublicKeyId(), meta.getTenantId());
|
||||||
|
}catch (Exception e){
|
||||||
|
throw new PayException("An error occurred while generating the public key,Please check the format and content of the configured public key");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,5 +76,31 @@ public class WechatPayProperties {
|
|||||||
* your pay server domain
|
* your pay server domain
|
||||||
*/
|
*/
|
||||||
private String domain;
|
private String domain;
|
||||||
|
|
||||||
|
|
||||||
|
private Boolean enableWechatPayPublic=false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wechat pay public key id
|
||||||
|
*/
|
||||||
|
private String wechatPayPublicKeyId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see <a href="https://pay.weixin.qq.com/doc/v3/merchant/4012154180#4.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">
|
||||||
|
* </a>
|
||||||
|
* wechat pay public key
|
||||||
|
*/
|
||||||
|
private String wechatPayPublicKeyPath;
|
||||||
|
|
||||||
|
private String wechatPayPublicKeyAbsolutePath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* see <a href="https://pay.weixin.qq.com/doc/v3/merchant/4012154180">
|
||||||
|
* Indicate whether to switch from the platform certificate to the WeChat Pay public key
|
||||||
|
* </a>
|
||||||
|
*/
|
||||||
|
private Boolean switchVerifySignMethod = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,13 @@ public enum WechatPayV3Type {
|
|||||||
MERCHANT_MEDIA_VIDEO(HttpMethod.POST, "%s/v3/merchant/media/video_upload"),
|
MERCHANT_MEDIA_VIDEO(HttpMethod.POST, "%s/v3/merchant/media/video_upload"),
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 付款码支付
|
||||||
|
*
|
||||||
|
* @since 1.0.0.RELEASE
|
||||||
|
*/
|
||||||
|
CODE(HttpMethod.POST, "%s/v3/pay/transactions/codepay"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信公众号支付或者小程序支付.
|
* 微信公众号支付或者小程序支付.
|
||||||
*
|
*
|
||||||
@@ -99,6 +106,13 @@ public enum WechatPayV3Type {
|
|||||||
* @since 1.0.0.RELEASE
|
* @since 1.0.0.RELEASE
|
||||||
*/
|
*/
|
||||||
CLOSE(HttpMethod.POST, "%s/v3/pay/transactions/out-trade-no/{out_trade_no}/close"),
|
CLOSE(HttpMethod.POST, "%s/v3/pay/transactions/out-trade-no/{out_trade_no}/close"),
|
||||||
|
/**
|
||||||
|
* 关闭订单.
|
||||||
|
*
|
||||||
|
* @since 1.0.0.RELEASE
|
||||||
|
*/
|
||||||
|
REVERSE(HttpMethod.POST, "%s/v3/pay/transactions/out-trade-no/{out_trade_no}/reverse"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信支付订单号查询API.
|
* 微信支付订单号查询API.
|
||||||
*
|
*
|
||||||
@@ -633,6 +647,7 @@ public enum WechatPayV3Type {
|
|||||||
|
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务商APP下单API.
|
* 服务商APP下单API.
|
||||||
*
|
*
|
||||||
@@ -704,7 +719,7 @@ public enum WechatPayV3Type {
|
|||||||
*
|
*
|
||||||
* @since 1.0.11.RELEASE
|
* @since 1.0.11.RELEASE
|
||||||
*/
|
*/
|
||||||
PROFITSHARING_RETURN_ORDERS_RESULT(HttpMethod.GET, "%s/v3/profitsharing/return-orders"),
|
PROFITSHARING_RETURN_ORDERS_RESULT(HttpMethod.GET, "%s/v3/profitsharing/return-orders/{out_return_no}"),
|
||||||
/**
|
/**
|
||||||
* 解冻剩余资金API.
|
* 解冻剩余资金API.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -27,13 +27,15 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
|
|||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
|
import org.bouncycastle.util.io.pem.PemObject;
|
||||||
|
import org.bouncycastle.util.io.pem.PemReader;
|
||||||
|
import org.springframework.core.io.FileSystemResource;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
import org.springframework.http.*;
|
import org.springframework.http.*;
|
||||||
import org.springframework.http.converter.HttpMessageConverter;
|
import org.springframework.http.converter.HttpMessageConverter;
|
||||||
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
|
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
|
||||||
import org.springframework.util.AlternativeJdkIdGenerator;
|
import org.springframework.util.*;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.Base64Utils;
|
|
||||||
import org.springframework.util.IdGenerator;
|
|
||||||
import org.springframework.web.client.RestOperations;
|
import org.springframework.web.client.RestOperations;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
import org.springframework.web.util.UriComponents;
|
import org.springframework.web.util.UriComponents;
|
||||||
@@ -44,12 +46,16 @@ import javax.crypto.NoSuchPaddingException;
|
|||||||
import javax.crypto.spec.GCMParameterSpec;
|
import javax.crypto.spec.GCMParameterSpec;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileReader;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
import java.security.cert.Certificate;
|
import java.security.cert.Certificate;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.security.interfaces.RSAPublicKey;
|
||||||
|
import java.security.spec.X509EncodedKeySpec;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -85,6 +91,11 @@ public class SignatureProvider {
|
|||||||
* 微信平台证书容器 key = 序列号 value = 证书对象
|
* 微信平台证书容器 key = 序列号 value = 证书对象
|
||||||
*/
|
*/
|
||||||
private static final Set<X509WechatCertificateInfo> CERTIFICATE_SET = Collections.synchronizedSet(new HashSet<>());
|
private static final Set<X509WechatCertificateInfo> CERTIFICATE_SET = Collections.synchronizedSet(new HashSet<>());
|
||||||
|
|
||||||
|
private static final Set<WeChatPublicKeyInfo> PUBLIC_KEY_SET = Collections.synchronizedSet(new HashSet<>());
|
||||||
|
|
||||||
|
private static final String PUBLIC_KYE_ID_PREFIX = "PUB_KEY_ID";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加密算法提供方 - BouncyCastle
|
* 加密算法提供方 - BouncyCastle
|
||||||
*/
|
*/
|
||||||
@@ -117,6 +128,10 @@ public class SignatureProvider {
|
|||||||
wechatMetaContainer.getTenantIds().forEach(this::refreshCertificate);
|
wechatMetaContainer.getTenantIds().forEach(this::refreshCertificate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void addWeChatPublicKey(WeChatPublicKeyInfo weChatPublicKeyInfo) {
|
||||||
|
PUBLIC_KEY_SET.add(weChatPublicKeyInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 我方请求前用 SHA256withRSA 加签,使用API证书.
|
* 我方请求前用 SHA256withRSA 加签,使用API证书.
|
||||||
@@ -171,7 +186,19 @@ public class SignatureProvider {
|
|||||||
* @return the boolean
|
* @return the boolean
|
||||||
*/
|
*/
|
||||||
public boolean responseSignVerify(ResponseSignVerifyParams params) {
|
public boolean responseSignVerify(ResponseSignVerifyParams params) {
|
||||||
|
log.debug("wechatpaySerial: {}", params.getWechatpaySerial());
|
||||||
|
boolean verifyResult= params.getWechatpaySerial().startsWith(PUBLIC_KYE_ID_PREFIX)?
|
||||||
|
responseSignVerifyWithWeChatPublicKeyInfo(params):
|
||||||
|
responseSignVerifyWithX509WechatCertificate(params);
|
||||||
|
log.debug("responseSignVerify: {}", verifyResult);
|
||||||
|
return verifyResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
*通过平台证书进行验签
|
||||||
|
*/
|
||||||
|
private boolean responseSignVerifyWithX509WechatCertificate(ResponseSignVerifyParams params){
|
||||||
|
log.debug("responseSignVerifyWithX509WechatCertificate: {}", params);
|
||||||
String wechatpaySerial = params.getWechatpaySerial();
|
String wechatpaySerial = params.getWechatpaySerial();
|
||||||
X509WechatCertificateInfo certificate = CERTIFICATE_SET.stream()
|
X509WechatCertificateInfo certificate = CERTIFICATE_SET.stream()
|
||||||
.filter(cert -> Objects.equals(wechatpaySerial, cert.getWechatPaySerial()))
|
.filter(cert -> Objects.equals(wechatpaySerial, cert.getWechatPaySerial()))
|
||||||
@@ -195,6 +222,30 @@ public class SignatureProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
*通过微信支付公钥进行验签
|
||||||
|
*/
|
||||||
|
private boolean responseSignVerifyWithWeChatPublicKeyInfo(ResponseSignVerifyParams params){
|
||||||
|
log.debug("responseSignVerifyWithWeChatPublicKeyInfo: {}", params);
|
||||||
|
String wechatpaySerial = params.getWechatpaySerial();
|
||||||
|
if (wechatpaySerial.startsWith(PUBLIC_KYE_ID_PREFIX)){
|
||||||
|
WeChatPublicKeyInfo info = PUBLIC_KEY_SET.stream()
|
||||||
|
.filter(key -> Objects.equals(wechatpaySerial, key.getPublicKeyId()))
|
||||||
|
.findAny()
|
||||||
|
.orElseThrow(() -> new PayException("cannot obtain the public key"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
final String signatureStr = createSign(params.getWechatpayTimestamp(), params.getWechatpayNonce(), params.getBody());
|
||||||
|
Signature signer = Signature.getInstance("SHA256withRSA", BC_PROVIDER);
|
||||||
|
signer.initVerify(info.getPublicKey());
|
||||||
|
signer.update(signatureStr.getBytes(StandardCharsets.UTF_8));
|
||||||
|
return signer.verify(Base64Utils.decodeFromString(params.getWechatpaySignature()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new PayException("An exception occurred during the response verification, the cause: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当我方服务器不存在平台证书或者证书同当前响应报文中的证书序列号不一致时应当刷新 调用/v3/certificates
|
* 当我方服务器不存在平台证书或者证书同当前响应报文中的证书序列号不一致时应当刷新 调用/v3/certificates
|
||||||
@@ -203,8 +254,12 @@ public class SignatureProvider {
|
|||||||
*/
|
*/
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
private synchronized void refreshCertificate(String tenantId) {
|
private synchronized void refreshCertificate(String tenantId) {
|
||||||
String url = WechatPayV3Type.CERT.uri(WeChatServer.CHINA);
|
|
||||||
|
|
||||||
|
WechatMetaBean wechatMetaBean = wechatMetaContainer.getWechatMeta(tenantId);
|
||||||
|
if (wechatMetaBean.getV3().getEnableWechatPayPublic() && !wechatMetaBean.getV3().getSwitchVerifySignMethod()){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String url = WechatPayV3Type.CERT.uri(WeChatServer.CHINA);
|
||||||
UriComponents uri = UriComponentsBuilder.fromHttpUrl(url).build();
|
UriComponents uri = UriComponentsBuilder.fromHttpUrl(url).build();
|
||||||
|
|
||||||
String canonicalUrl = uri.getPath();
|
String canonicalUrl = uri.getPath();
|
||||||
@@ -299,18 +354,42 @@ public class SignatureProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String encryptRequestMessage(String message, WechatMetaBean wechatMetaBean) {
|
||||||
|
PublicKey publicKey;
|
||||||
|
if (wechatMetaBean.getEnableWechatPayPublicEncrypt()){
|
||||||
|
WeChatPublicKeyInfo info=this.getWechatPublicKeyInfo(wechatMetaBean.getTenantId());
|
||||||
|
publicKey=info.getPublicKey();
|
||||||
|
}else {
|
||||||
|
X509WechatCertificateInfo certificate = getCertificate(wechatMetaBean.getTenantId());
|
||||||
|
final X509Certificate x509Certificate = certificate.getX509Certificate();
|
||||||
|
publicKey=x509Certificate.getPublicKey();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding", BC_PROVIDER);
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||||
|
byte[] data = message.getBytes(StandardCharsets.UTF_8);
|
||||||
|
byte[] cipherData = cipher.doFinal(data);
|
||||||
|
return Base64Utils.encodeToString(cipherData);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new PayException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对请求敏感字段进行加密
|
* 对请求敏感字段进行加密
|
||||||
*
|
* 只有使用平台证书进行验签与签名的商户使用该方法
|
||||||
* @param message the message
|
* @param message the message
|
||||||
* @param certificate the certificate
|
* @param publicKey the wechatPubicKey certificate
|
||||||
* @return encrypt message
|
* @return encrypt message
|
||||||
* @since 1.0.6.RELEASE
|
* @since 1.0.6.RELEASE
|
||||||
*/
|
*/
|
||||||
public String encryptRequestMessage(String message, Certificate certificate) {
|
@Deprecated
|
||||||
|
public String encryptRequestMessage(String message, RSAPublicKey publicKey) {
|
||||||
try {
|
try {
|
||||||
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding", BC_PROVIDER);
|
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding", BC_PROVIDER);
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, certificate.getPublicKey());
|
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||||
|
|
||||||
byte[] data = message.getBytes(StandardCharsets.UTF_8);
|
byte[] data = message.getBytes(StandardCharsets.UTF_8);
|
||||||
byte[] cipherData = cipher.doFinal(data);
|
byte[] cipherData = cipher.doFinal(data);
|
||||||
@@ -350,7 +429,7 @@ public class SignatureProvider {
|
|||||||
* @param tenantId the tenant id
|
* @param tenantId the tenant id
|
||||||
* @return the x 509 wechat certificate info
|
* @return the x 509 wechat certificate info
|
||||||
*/
|
*/
|
||||||
public X509WechatCertificateInfo getCertificate(String tenantId) {
|
private X509WechatCertificateInfo getCertificate(String tenantId) {
|
||||||
|
|
||||||
return CERTIFICATE_SET.stream()
|
return CERTIFICATE_SET.stream()
|
||||||
.filter(cert -> Objects.equals(tenantId, cert.getTenantId()))
|
.filter(cert -> Objects.equals(tenantId, cert.getTenantId()))
|
||||||
@@ -364,6 +443,15 @@ public class SignatureProvider {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WeChatPublicKeyInfo getWechatPublicKeyInfo(String tenantId) {
|
||||||
|
return PUBLIC_KEY_SET.stream()
|
||||||
|
.filter(publicKeyInfo -> Objects.equals(tenantId, publicKeyInfo.getTenantId()))
|
||||||
|
.findAny()
|
||||||
|
.orElseThrow(
|
||||||
|
() -> new PayException("cannot obtain the public key")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wechat meta container.
|
* Wechat meta container.
|
||||||
@@ -395,4 +483,21 @@ public class SignatureProvider {
|
|||||||
.collect(Collectors.joining("\n", "", "\n"));
|
.collect(Collectors.joining("\n", "", "\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSwitchVerifySignMethod(String tenantId) {
|
||||||
|
|
||||||
|
return wechatMetaContainer.getWechatMeta(tenantId).getV3().getSwitchVerifySignMethod()
|
||||||
|
&& wechatMetaContainer.getWechatMeta(tenantId).getV3().getEnableWechatPayPublic();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getWechatPublicKeyId(String tenantId) {
|
||||||
|
return wechatMetaContainer.getWechatMeta(tenantId).getV3().getWechatPayPublicKeyId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getWechatPaySerial(WechatMetaBean wechatMetaBean) {
|
||||||
|
if (wechatMetaBean.getEnableWechatPayPublicEncrypt()){
|
||||||
|
return this.getWechatPublicKeyInfo(wechatMetaBean.getTenantId()).getPublicKeyId();
|
||||||
|
}else {
|
||||||
|
return this.getCertificate(wechatMetaBean.getTenantId()).getWechatPaySerial();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package cn.felord.payment.wechat.v3;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.security.interfaces.RSAPublicKey;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class WeChatPublicKeyInfo {
|
||||||
|
|
||||||
|
private RSAPublicKey publicKey;
|
||||||
|
|
||||||
|
private String publicKeyId;
|
||||||
|
|
||||||
|
private String tenantId;
|
||||||
|
|
||||||
|
public WeChatPublicKeyInfo(RSAPublicKey publicKey, String publicKeyId, String tenantId) {
|
||||||
|
this.publicKeyId = publicKeyId;
|
||||||
|
this.tenantId = tenantId;
|
||||||
|
this.publicKey = publicKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WeChatPublicKeyInfo() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -77,18 +77,16 @@ public class WechatBatchTransferApi extends AbstractApi {
|
|||||||
List<CreateBatchTransferParams.TransferDetailListItem> transferDetailList = createBatchTransferParams.getTransferDetailList();
|
List<CreateBatchTransferParams.TransferDetailListItem> transferDetailList = createBatchTransferParams.getTransferDetailList();
|
||||||
|
|
||||||
SignatureProvider signatureProvider = this.client().signatureProvider();
|
SignatureProvider signatureProvider = this.client().signatureProvider();
|
||||||
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
|
|
||||||
final X509Certificate x509Certificate = certificate.getX509Certificate();
|
|
||||||
List<CreateBatchTransferParams.TransferDetailListItem> encrypted = transferDetailList.stream()
|
List<CreateBatchTransferParams.TransferDetailListItem> encrypted = transferDetailList.stream()
|
||||||
.peek(transferDetailListItem -> {
|
.peek(transferDetailListItem -> {
|
||||||
String userName = transferDetailListItem.getUserName();
|
String userName = transferDetailListItem.getUserName();
|
||||||
if (StringUtils.hasText(userName)) {
|
if (StringUtils.hasText(userName)) {
|
||||||
String encryptedUserName = signatureProvider.encryptRequestMessage(userName, x509Certificate);
|
String encryptedUserName = signatureProvider.encryptRequestMessage(userName, this.wechatMetaBean());
|
||||||
transferDetailListItem.setUserName(encryptedUserName);
|
transferDetailListItem.setUserName(encryptedUserName);
|
||||||
}
|
}
|
||||||
String userIdCard = transferDetailListItem.getUserIdCard();
|
String userIdCard = transferDetailListItem.getUserIdCard();
|
||||||
if (StringUtils.hasText(userIdCard)) {
|
if (StringUtils.hasText(userIdCard)) {
|
||||||
String encryptedUserIdCard = signatureProvider.encryptRequestMessage(userIdCard, x509Certificate);
|
String encryptedUserIdCard = signatureProvider.encryptRequestMessage(userIdCard, this.wechatMetaBean());
|
||||||
transferDetailListItem.setUserIdCard(encryptedUserIdCard);
|
transferDetailListItem.setUserIdCard(encryptedUserIdCard);
|
||||||
}
|
}
|
||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
@@ -98,7 +96,7 @@ public class WechatBatchTransferApi extends AbstractApi {
|
|||||||
.build()
|
.build()
|
||||||
.toUri();
|
.toUri();
|
||||||
HttpHeaders httpHeaders = new HttpHeaders();
|
HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
|
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
|
||||||
return Post(uri, createBatchTransferParams, httpHeaders);
|
return Post(uri, createBatchTransferParams, httpHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,11 +56,8 @@ public class WechatCapitalApi extends AbstractApi{
|
|||||||
this.client().withType(WechatPayV3Type.CAPITAL_SEARCH, accountNumber)
|
this.client().withType(WechatPayV3Type.CAPITAL_SEARCH, accountNumber)
|
||||||
.function((type, param) -> {
|
.function((type, param) -> {
|
||||||
SignatureProvider signatureProvider = this.client().signatureProvider();
|
SignatureProvider signatureProvider = this.client().signatureProvider();
|
||||||
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
|
|
||||||
final X509Certificate x509Certificate = certificate.getX509Certificate();
|
|
||||||
|
|
||||||
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
|
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
|
||||||
.queryParam("account_number", signatureProvider.encryptRequestMessage(param,x509Certificate))
|
.queryParam("account_number", signatureProvider.encryptRequestMessage(param,this.wechatMetaBean()))
|
||||||
.build()
|
.build()
|
||||||
.toUri();
|
.toUri();
|
||||||
return Get(uri);
|
return Get(uri);
|
||||||
|
|||||||
@@ -56,6 +56,29 @@ public class WechatDirectPayApi extends AbstractApi {
|
|||||||
super(wechatPayClient, tenantId);
|
super(wechatPayClient, tenantId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 付款码支付API
|
||||||
|
*
|
||||||
|
* @param payParams the pay params
|
||||||
|
* @return the wechat response entity
|
||||||
|
*/
|
||||||
|
public WechatResponseEntity<ObjectNode> codePay(PayParams payParams) {
|
||||||
|
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
|
||||||
|
this.client().withType(WechatPayV3Type.CODE, payParams)
|
||||||
|
.function(this::payFunction)
|
||||||
|
.consumer(responseEntity -> {
|
||||||
|
ObjectNode body = responseEntity.getBody();
|
||||||
|
if (Objects.isNull(body)) {
|
||||||
|
throw new PayException("response body cannot be resolved");
|
||||||
|
}
|
||||||
|
wechatResponseEntity.setHttpStatus(responseEntity.getStatusCodeValue());
|
||||||
|
wechatResponseEntity.setBody(body);
|
||||||
|
})
|
||||||
|
.request();
|
||||||
|
return wechatResponseEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* APP下单API
|
* APP下单API
|
||||||
*
|
*
|
||||||
@@ -185,8 +208,10 @@ public class WechatDirectPayApi extends AbstractApi {
|
|||||||
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
|
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
|
||||||
payParams.setAppid(v3.getAppId());
|
payParams.setAppid(v3.getAppId());
|
||||||
payParams.setMchid(v3.getMchId());
|
payParams.setMchid(v3.getMchId());
|
||||||
|
if (!type.equals(WechatPayV3Type.CODE)){
|
||||||
String notifyUrl = v3.getDomain().concat(payParams.getNotifyUrl());
|
String notifyUrl = v3.getDomain().concat(payParams.getNotifyUrl());
|
||||||
payParams.setNotifyUrl(notifyUrl);
|
payParams.setNotifyUrl(notifyUrl);
|
||||||
|
}
|
||||||
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
|
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
|
||||||
.build()
|
.build()
|
||||||
.toUri();
|
.toUri();
|
||||||
@@ -252,6 +277,21 @@ public class WechatDirectPayApi extends AbstractApi {
|
|||||||
return wechatResponseEntity;
|
return wechatResponseEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 撤销API
|
||||||
|
*
|
||||||
|
* @param outTradeNo the out trade no
|
||||||
|
* @return the wechat response entity
|
||||||
|
*/
|
||||||
|
public WechatResponseEntity<ObjectNode> reverse(String outTradeNo) {
|
||||||
|
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
|
||||||
|
this.client().withType(WechatPayV3Type.REVERSE, outTradeNo)
|
||||||
|
.function(this::reverseOutTradeNoFunction)
|
||||||
|
.consumer(wechatResponseEntity::convert)
|
||||||
|
.request();
|
||||||
|
return wechatResponseEntity;
|
||||||
|
}
|
||||||
|
|
||||||
private RequestEntity<?> closeByOutTradeNoFunction(WechatPayV3Type type, String outTradeNo) {
|
private RequestEntity<?> closeByOutTradeNoFunction(WechatPayV3Type type, String outTradeNo) {
|
||||||
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
|
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
|
||||||
|
|
||||||
@@ -265,6 +305,20 @@ public class WechatDirectPayApi extends AbstractApi {
|
|||||||
return Post(uri, queryParams);
|
return Post(uri, queryParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private RequestEntity<?> reverseOutTradeNoFunction(WechatPayV3Type type, String outTradeNo) {
|
||||||
|
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
|
||||||
|
|
||||||
|
Map<String, String> queryParams = new HashMap<>(1);
|
||||||
|
queryParams.put("mchid", v3.getMchId());
|
||||||
|
queryParams.put("appid", v3.getAppId());
|
||||||
|
|
||||||
|
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
|
||||||
|
.build()
|
||||||
|
.expand(outTradeNo)
|
||||||
|
.toUri();
|
||||||
|
return Post(uri, queryParams);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 申请退款API
|
* 申请退款API
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -47,4 +47,8 @@ public class WechatMetaBean {
|
|||||||
*/
|
*/
|
||||||
private WechatPayProperties.V3 v3;
|
private WechatPayProperties.V3 v3;
|
||||||
|
|
||||||
|
|
||||||
|
public Boolean getEnableWechatPayPublicEncrypt() {
|
||||||
|
return v3.getEnableWechatPayPublic();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,8 +79,6 @@ public class WechatPartnerProfitsharingApi extends AbstractApi {
|
|||||||
.function((wechatPayV3Type, params) -> {
|
.function((wechatPayV3Type, params) -> {
|
||||||
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
|
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
|
||||||
SignatureProvider signatureProvider = this.client().signatureProvider();
|
SignatureProvider signatureProvider = this.client().signatureProvider();
|
||||||
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
|
|
||||||
final X509Certificate x509Certificate = certificate.getX509Certificate();
|
|
||||||
params.setAppid(v3.getAppId());
|
params.setAppid(v3.getAppId());
|
||||||
List<Receiver> receivers = params.getReceivers();
|
List<Receiver> receivers = params.getReceivers();
|
||||||
if (!CollectionUtils.isEmpty(receivers)) {
|
if (!CollectionUtils.isEmpty(receivers)) {
|
||||||
@@ -88,7 +86,7 @@ public class WechatPartnerProfitsharingApi extends AbstractApi {
|
|||||||
.peek(receiversItem -> {
|
.peek(receiversItem -> {
|
||||||
String name = receiversItem.getName();
|
String name = receiversItem.getName();
|
||||||
if (StringUtils.hasText(name)) {
|
if (StringUtils.hasText(name)) {
|
||||||
String encryptedName = signatureProvider.encryptRequestMessage(name, x509Certificate);
|
String encryptedName = signatureProvider.encryptRequestMessage(name,this.wechatMetaBean());
|
||||||
receiversItem.setName(encryptedName);
|
receiversItem.setName(encryptedName);
|
||||||
}
|
}
|
||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
@@ -98,7 +96,7 @@ public class WechatPartnerProfitsharingApi extends AbstractApi {
|
|||||||
.build()
|
.build()
|
||||||
.toUri();
|
.toUri();
|
||||||
HttpHeaders httpHeaders = new HttpHeaders();
|
HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
|
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
|
||||||
return Post(uri, params, httpHeaders);
|
return Post(uri, params, httpHeaders);
|
||||||
})
|
})
|
||||||
.consumer(wechatResponseEntity::convert)
|
.consumer(wechatResponseEntity::convert)
|
||||||
@@ -294,19 +292,17 @@ public class WechatPartnerProfitsharingApi extends AbstractApi {
|
|||||||
.function((wechatPayV3Type, params) -> {
|
.function((wechatPayV3Type, params) -> {
|
||||||
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
|
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
|
||||||
SignatureProvider signatureProvider = this.client().signatureProvider();
|
SignatureProvider signatureProvider = this.client().signatureProvider();
|
||||||
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
|
|
||||||
final X509Certificate x509Certificate = certificate.getX509Certificate();
|
|
||||||
params.setAppid(v3.getAppId());
|
params.setAppid(v3.getAppId());
|
||||||
|
|
||||||
if (ReceiverType.MERCHANT_ID.equals(params.getType())) {
|
if (ReceiverType.MERCHANT_ID.equals(params.getType())) {
|
||||||
String encryptedName = signatureProvider.encryptRequestMessage(params.getName(), x509Certificate);
|
String encryptedName = signatureProvider.encryptRequestMessage(params.getName(), this.wechatMetaBean());
|
||||||
params.setName(encryptedName);
|
params.setName(encryptedName);
|
||||||
}
|
}
|
||||||
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
|
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
|
||||||
.build()
|
.build()
|
||||||
.toUri();
|
.toUri();
|
||||||
HttpHeaders httpHeaders = new HttpHeaders();
|
HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
|
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
|
||||||
return Post(uri, params, httpHeaders);
|
return Post(uri, params, httpHeaders);
|
||||||
})
|
})
|
||||||
.consumer(wechatResponseEntity::convert)
|
.consumer(wechatResponseEntity::convert)
|
||||||
|
|||||||
@@ -63,14 +63,12 @@ public class WechatPartnerSpecialMchApi extends AbstractApi {
|
|||||||
this.client().withType(WechatPayV3Type.SPEC_MCH_APPLY_PARTNER, params)
|
this.client().withType(WechatPayV3Type.SPEC_MCH_APPLY_PARTNER, params)
|
||||||
.function((wechatPayV3Type, applymentParams) -> {
|
.function((wechatPayV3Type, applymentParams) -> {
|
||||||
SignatureProvider signatureProvider = this.client().signatureProvider();
|
SignatureProvider signatureProvider = this.client().signatureProvider();
|
||||||
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
|
ApplymentParams applyRequestParams = this.convert(applymentParams, signatureProvider);
|
||||||
final X509Certificate x509Certificate = certificate.getX509Certificate();
|
|
||||||
ApplymentParams applyRequestParams = this.convert(applymentParams, signatureProvider, x509Certificate);
|
|
||||||
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
|
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
|
||||||
.build()
|
.build()
|
||||||
.toUri();
|
.toUri();
|
||||||
HttpHeaders httpHeaders = new HttpHeaders();
|
HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
|
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
|
||||||
return Post(uri, applyRequestParams, httpHeaders);
|
return Post(uri, applyRequestParams, httpHeaders);
|
||||||
})
|
})
|
||||||
.consumer(wechatResponseEntity::convert)
|
.consumer(wechatResponseEntity::convert)
|
||||||
@@ -133,17 +131,15 @@ public class WechatPartnerSpecialMchApi extends AbstractApi {
|
|||||||
this.client().withType(WechatPayV3Type.SPEC_MCH_SUB_MODIFY, params)
|
this.client().withType(WechatPayV3Type.SPEC_MCH_SUB_MODIFY, params)
|
||||||
.function((type, subMchModifyParams) -> {
|
.function((type, subMchModifyParams) -> {
|
||||||
SignatureProvider signatureProvider = this.client().signatureProvider();
|
SignatureProvider signatureProvider = this.client().signatureProvider();
|
||||||
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
|
|
||||||
final X509Certificate x509Certificate = certificate.getX509Certificate();
|
|
||||||
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
|
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
|
||||||
.build()
|
.build()
|
||||||
.expand(subMchModifyParams.getSubMchid())
|
.expand(subMchModifyParams.getSubMchid())
|
||||||
.toUri();
|
.toUri();
|
||||||
|
|
||||||
subMchModifyParams.setSubMchid(null);
|
subMchModifyParams.setSubMchid(null);
|
||||||
subMchModifyParams.setAccountNumber(signatureProvider.encryptRequestMessage(subMchModifyParams.getAccountNumber(), x509Certificate));
|
subMchModifyParams.setAccountNumber(signatureProvider.encryptRequestMessage(subMchModifyParams.getAccountNumber(), this.wechatMetaBean()));
|
||||||
HttpHeaders httpHeaders = new HttpHeaders();
|
HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
|
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
|
||||||
return Post(uri, subMchModifyParams, httpHeaders);
|
return Post(uri, subMchModifyParams, httpHeaders);
|
||||||
})
|
})
|
||||||
.consumer(wechatResponseEntity::convert)
|
.consumer(wechatResponseEntity::convert)
|
||||||
@@ -175,55 +171,55 @@ public class WechatPartnerSpecialMchApi extends AbstractApi {
|
|||||||
return wechatResponseEntity;
|
return wechatResponseEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ApplymentParams convert(ApplymentParams applymentParams, SignatureProvider signatureProvider, final X509Certificate x509Certificate) {
|
private ApplymentParams convert(ApplymentParams applymentParams, SignatureProvider signatureProvider) {
|
||||||
|
|
||||||
ContactInfo contactInfo = applymentParams.getContactInfo();
|
ContactInfo contactInfo = applymentParams.getContactInfo();
|
||||||
contactInfo.setContactName(signatureProvider.encryptRequestMessage(contactInfo.getContactName(), x509Certificate));
|
contactInfo.setContactName(signatureProvider.encryptRequestMessage(contactInfo.getContactName(), this.wechatMetaBean()));
|
||||||
String contactIdNumber = contactInfo.getContactIdNumber();
|
String contactIdNumber = contactInfo.getContactIdNumber();
|
||||||
if (contactIdNumber != null) {
|
if (contactIdNumber != null) {
|
||||||
contactInfo.setContactIdNumber(signatureProvider.encryptRequestMessage(contactIdNumber, x509Certificate));
|
contactInfo.setContactIdNumber(signatureProvider.encryptRequestMessage(contactIdNumber,this.wechatMetaBean()));
|
||||||
}
|
}
|
||||||
String openid = contactInfo.getOpenid();
|
String openid = contactInfo.getOpenid();
|
||||||
if (openid != null) {
|
if (openid != null) {
|
||||||
contactInfo.setOpenid(signatureProvider.encryptRequestMessage(openid, x509Certificate));
|
contactInfo.setOpenid(signatureProvider.encryptRequestMessage(openid,this.wechatMetaBean()));
|
||||||
}
|
}
|
||||||
contactInfo.setMobilePhone(signatureProvider.encryptRequestMessage(contactInfo.getMobilePhone(), x509Certificate));
|
contactInfo.setMobilePhone(signatureProvider.encryptRequestMessage(contactInfo.getMobilePhone(), this.wechatMetaBean()));
|
||||||
contactInfo.setContactEmail(signatureProvider.encryptRequestMessage(contactInfo.getContactEmail(), x509Certificate));
|
contactInfo.setContactEmail(signatureProvider.encryptRequestMessage(contactInfo.getContactEmail(), this.wechatMetaBean()));
|
||||||
|
|
||||||
SubjectInfo subjectInfo = applymentParams.getSubjectInfo();
|
SubjectInfo subjectInfo = applymentParams.getSubjectInfo();
|
||||||
IdentityInfo identityInfo = subjectInfo.getIdentityInfo();
|
IdentityInfo identityInfo = subjectInfo.getIdentityInfo();
|
||||||
|
|
||||||
IdCardInfo idCardInfo = identityInfo.getIdCardInfo();
|
IdCardInfo idCardInfo = identityInfo.getIdCardInfo();
|
||||||
if (idCardInfo != null) {
|
if (idCardInfo != null) {
|
||||||
idCardInfo.setIdCardName(signatureProvider.encryptRequestMessage(idCardInfo.getIdCardName(), x509Certificate));
|
idCardInfo.setIdCardName(signatureProvider.encryptRequestMessage(idCardInfo.getIdCardName(), this.wechatMetaBean()));
|
||||||
idCardInfo.setIdCardNumber(signatureProvider.encryptRequestMessage(idCardInfo.getIdCardNumber(), x509Certificate));
|
idCardInfo.setIdCardNumber(signatureProvider.encryptRequestMessage(idCardInfo.getIdCardNumber(), this.wechatMetaBean()));
|
||||||
String idCardAddress = idCardInfo.getIdCardAddress();
|
String idCardAddress = idCardInfo.getIdCardAddress();
|
||||||
if (StringUtils.hasText(idCardAddress)){
|
if (StringUtils.hasText(idCardAddress)){
|
||||||
idCardInfo.setIdCardAddress(signatureProvider.encryptRequestMessage(idCardAddress, x509Certificate));
|
idCardInfo.setIdCardAddress(signatureProvider.encryptRequestMessage(idCardAddress,this.wechatMetaBean()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IdDocInfo idDocInfo = identityInfo.getIdDocInfo();
|
IdDocInfo idDocInfo = identityInfo.getIdDocInfo();
|
||||||
if (idDocInfo != null) {
|
if (idDocInfo != null) {
|
||||||
idDocInfo.setIdDocName(signatureProvider.encryptRequestMessage(idDocInfo.getIdDocName(), x509Certificate));
|
idDocInfo.setIdDocName(signatureProvider.encryptRequestMessage(idDocInfo.getIdDocName(), this.wechatMetaBean()));
|
||||||
idDocInfo.setIdDocNumber(signatureProvider.encryptRequestMessage(idDocInfo.getIdDocNumber(), x509Certificate));
|
idDocInfo.setIdDocNumber(signatureProvider.encryptRequestMessage(idDocInfo.getIdDocNumber(), this.wechatMetaBean()));
|
||||||
String idDocAddress = idDocInfo.getIdDocAddress();
|
String idDocAddress = idDocInfo.getIdDocAddress();
|
||||||
if (StringUtils.hasText(idDocAddress)){
|
if (StringUtils.hasText(idDocAddress)){
|
||||||
idDocInfo.setIdDocAddress(signatureProvider.encryptRequestMessage(idDocAddress, x509Certificate));
|
idDocInfo.setIdDocAddress(signatureProvider.encryptRequestMessage(idDocAddress,this.wechatMetaBean()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
List<UboInfoListItem> uboInfoList = subjectInfo.getUboInfoList();
|
List<UboInfoListItem> uboInfoList = subjectInfo.getUboInfoList();
|
||||||
if (!CollectionUtils.isEmpty(uboInfoList)) {
|
if (!CollectionUtils.isEmpty(uboInfoList)) {
|
||||||
uboInfoList.forEach(uboInfoListItem -> {
|
uboInfoList.forEach(uboInfoListItem -> {
|
||||||
uboInfoListItem.setUboIdDocName(signatureProvider.encryptRequestMessage(uboInfoListItem.getUboIdDocName(), x509Certificate));
|
uboInfoListItem.setUboIdDocName(signatureProvider.encryptRequestMessage(uboInfoListItem.getUboIdDocName(), this.wechatMetaBean()));
|
||||||
uboInfoListItem.setUboIdDocNumber(signatureProvider.encryptRequestMessage(uboInfoListItem.getUboIdDocNumber(), x509Certificate));
|
uboInfoListItem.setUboIdDocNumber(signatureProvider.encryptRequestMessage(uboInfoListItem.getUboIdDocNumber(), this.wechatMetaBean()));
|
||||||
uboInfoListItem.setUboIdDocAddress(signatureProvider.encryptRequestMessage(uboInfoListItem.getUboIdDocAddress(), x509Certificate));
|
uboInfoListItem.setUboIdDocAddress(signatureProvider.encryptRequestMessage(uboInfoListItem.getUboIdDocAddress(), this.wechatMetaBean()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
BankAccountInfo bankAccountInfo = applymentParams.getBankAccountInfo();
|
BankAccountInfo bankAccountInfo = applymentParams.getBankAccountInfo();
|
||||||
|
|
||||||
bankAccountInfo.setAccountName(signatureProvider.encryptRequestMessage(bankAccountInfo.getAccountName(), x509Certificate));
|
bankAccountInfo.setAccountName(signatureProvider.encryptRequestMessage(bankAccountInfo.getAccountName(), this.wechatMetaBean()));
|
||||||
bankAccountInfo.setAccountNumber(signatureProvider.encryptRequestMessage(bankAccountInfo.getAccountNumber(), x509Certificate));
|
bankAccountInfo.setAccountNumber(signatureProvider.encryptRequestMessage(bankAccountInfo.getAccountNumber(), this.wechatMetaBean()));
|
||||||
|
|
||||||
return applymentParams;
|
return applymentParams;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -232,6 +232,11 @@ public class WechatPayClient {
|
|||||||
// 避免出现因为中文导致的 HttpRetryException
|
// 避免出现因为中文导致的 HttpRetryException
|
||||||
httpHeaders.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8"));
|
httpHeaders.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (signatureProvider.isSwitchVerifySignMethod(tenantId)){
|
||||||
|
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPublicKeyId(tenantId));
|
||||||
|
}
|
||||||
|
|
||||||
httpHeaders.add("Authorization", authorization);
|
httpHeaders.add("Authorization", authorization);
|
||||||
httpHeaders.add("User-Agent", "X-Pay-Service");
|
httpHeaders.add("User-Agent", "X-Pay-Service");
|
||||||
httpHeaders.remove("Meta-Info");
|
httpHeaders.remove("Meta-Info");
|
||||||
|
|||||||
@@ -77,8 +77,6 @@ public class WechatProfitsharingApi extends AbstractApi {
|
|||||||
.function((wechatPayV3Type, params) -> {
|
.function((wechatPayV3Type, params) -> {
|
||||||
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
|
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
|
||||||
SignatureProvider signatureProvider = this.client().signatureProvider();
|
SignatureProvider signatureProvider = this.client().signatureProvider();
|
||||||
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
|
|
||||||
final X509Certificate x509Certificate = certificate.getX509Certificate();
|
|
||||||
params.setAppid(v3.getAppId());
|
params.setAppid(v3.getAppId());
|
||||||
List<Receiver> receivers = params.getReceivers();
|
List<Receiver> receivers = params.getReceivers();
|
||||||
if (!CollectionUtils.isEmpty(receivers)) {
|
if (!CollectionUtils.isEmpty(receivers)) {
|
||||||
@@ -86,7 +84,7 @@ public class WechatProfitsharingApi extends AbstractApi {
|
|||||||
.peek(receiversItem -> {
|
.peek(receiversItem -> {
|
||||||
String name = receiversItem.getName();
|
String name = receiversItem.getName();
|
||||||
if (StringUtils.hasText(name)) {
|
if (StringUtils.hasText(name)) {
|
||||||
String encryptedName = signatureProvider.encryptRequestMessage(name, x509Certificate);
|
String encryptedName = signatureProvider.encryptRequestMessage(name,this.wechatMetaBean());
|
||||||
receiversItem.setName(encryptedName);
|
receiversItem.setName(encryptedName);
|
||||||
}
|
}
|
||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
@@ -96,7 +94,7 @@ public class WechatProfitsharingApi extends AbstractApi {
|
|||||||
.build()
|
.build()
|
||||||
.toUri();
|
.toUri();
|
||||||
HttpHeaders httpHeaders = new HttpHeaders();
|
HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
|
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
|
||||||
return Post(uri, params, httpHeaders);
|
return Post(uri, params, httpHeaders);
|
||||||
})
|
})
|
||||||
.consumer(wechatResponseEntity::convert)
|
.consumer(wechatResponseEntity::convert)
|
||||||
@@ -263,19 +261,17 @@ public class WechatProfitsharingApi extends AbstractApi {
|
|||||||
.function((wechatPayV3Type, params) -> {
|
.function((wechatPayV3Type, params) -> {
|
||||||
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
|
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
|
||||||
SignatureProvider signatureProvider = this.client().signatureProvider();
|
SignatureProvider signatureProvider = this.client().signatureProvider();
|
||||||
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
|
|
||||||
final X509Certificate x509Certificate = certificate.getX509Certificate();
|
|
||||||
params.setAppid(v3.getAppId());
|
params.setAppid(v3.getAppId());
|
||||||
String name = params.getName();
|
String name = params.getName();
|
||||||
if (StringUtils.hasText(name)) {
|
if (StringUtils.hasText(name)) {
|
||||||
String encryptedName = signatureProvider.encryptRequestMessage(name, x509Certificate);
|
String encryptedName = signatureProvider.encryptRequestMessage(name,this.wechatMetaBean());
|
||||||
params.setName(encryptedName);
|
params.setName(encryptedName);
|
||||||
}
|
}
|
||||||
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
|
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
|
||||||
.build()
|
.build()
|
||||||
.toUri();
|
.toUri();
|
||||||
HttpHeaders httpHeaders = new HttpHeaders();
|
HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
|
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
|
||||||
return Post(uri, params, httpHeaders);
|
return Post(uri, params, httpHeaders);
|
||||||
})
|
})
|
||||||
.consumer(wechatResponseEntity::convert)
|
.consumer(wechatResponseEntity::convert)
|
||||||
|
|||||||
@@ -65,15 +65,13 @@ public class WechatSmartGuideApi extends AbstractApi {
|
|||||||
this.client().withType(WechatPayV3Type.SMART_GUIDES, params)
|
this.client().withType(WechatPayV3Type.SMART_GUIDES, params)
|
||||||
.function((wechatPayV3Type, smartGuidesParams) -> {
|
.function((wechatPayV3Type, smartGuidesParams) -> {
|
||||||
SignatureProvider signatureProvider = this.client().signatureProvider();
|
SignatureProvider signatureProvider = this.client().signatureProvider();
|
||||||
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
|
smartGuidesParams.setName(signatureProvider.encryptRequestMessage(smartGuidesParams.getName(), this.wechatMetaBean()));
|
||||||
final X509Certificate x509Certificate = certificate.getX509Certificate();
|
smartGuidesParams.setMobile(signatureProvider.encryptRequestMessage(smartGuidesParams.getMobile(), this.wechatMetaBean()));
|
||||||
smartGuidesParams.setName(signatureProvider.encryptRequestMessage(smartGuidesParams.getName(), x509Certificate));
|
|
||||||
smartGuidesParams.setMobile(signatureProvider.encryptRequestMessage(smartGuidesParams.getMobile(), x509Certificate));
|
|
||||||
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
|
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
|
||||||
.build()
|
.build()
|
||||||
.toUri();
|
.toUri();
|
||||||
HttpHeaders httpHeaders = new HttpHeaders();
|
HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
|
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
|
||||||
return Post(uri, smartGuidesParams, httpHeaders);
|
return Post(uri, smartGuidesParams, httpHeaders);
|
||||||
})
|
})
|
||||||
.consumer(wechatResponseEntity::convert)
|
.consumer(wechatResponseEntity::convert)
|
||||||
@@ -137,10 +135,8 @@ public class WechatSmartGuideApi extends AbstractApi {
|
|||||||
String mobile = smartGuidesQueryParams.getMobile();
|
String mobile = smartGuidesQueryParams.getMobile();
|
||||||
if (mobile != null) {
|
if (mobile != null) {
|
||||||
SignatureProvider signatureProvider = this.client().signatureProvider();
|
SignatureProvider signatureProvider = this.client().signatureProvider();
|
||||||
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
|
queryParams.add("mobile", signatureProvider.encryptRequestMessage(mobile,this.wechatMetaBean()));
|
||||||
final X509Certificate x509Certificate = certificate.getX509Certificate();
|
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
|
||||||
queryParams.add("mobile", signatureProvider.encryptRequestMessage(mobile, x509Certificate));
|
|
||||||
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
|
|
||||||
}
|
}
|
||||||
String workId = smartGuidesQueryParams.getWorkId();
|
String workId = smartGuidesQueryParams.getWorkId();
|
||||||
if (workId != null) {
|
if (workId != null) {
|
||||||
@@ -177,15 +173,13 @@ public class WechatSmartGuideApi extends AbstractApi {
|
|||||||
this.client().withType(WechatPayV3Type.SMART_GUIDES_MODIFY, params)
|
this.client().withType(WechatPayV3Type.SMART_GUIDES_MODIFY, params)
|
||||||
.function((wechatPayV3Type, smartGuidesParams) -> {
|
.function((wechatPayV3Type, smartGuidesParams) -> {
|
||||||
SignatureProvider signatureProvider = this.client().signatureProvider();
|
SignatureProvider signatureProvider = this.client().signatureProvider();
|
||||||
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
|
smartGuidesParams.setName(signatureProvider.encryptRequestMessage(smartGuidesParams.getName(), this.wechatMetaBean()));
|
||||||
final X509Certificate x509Certificate = certificate.getX509Certificate();
|
smartGuidesParams.setMobile(signatureProvider.encryptRequestMessage(smartGuidesParams.getMobile(), this.wechatMetaBean()));
|
||||||
smartGuidesParams.setName(signatureProvider.encryptRequestMessage(smartGuidesParams.getName(), x509Certificate));
|
|
||||||
smartGuidesParams.setMobile(signatureProvider.encryptRequestMessage(smartGuidesParams.getMobile(), x509Certificate));
|
|
||||||
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
|
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
|
||||||
.build()
|
.build()
|
||||||
.toUri();
|
.toUri();
|
||||||
HttpHeaders httpHeaders = new HttpHeaders();
|
HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
|
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
|
||||||
return Patch(uri, smartGuidesParams, httpHeaders);
|
return Patch(uri, smartGuidesParams, httpHeaders);
|
||||||
})
|
})
|
||||||
.consumer(wechatResponseEntity::convert)
|
.consumer(wechatResponseEntity::convert)
|
||||||
|
|||||||
@@ -71,12 +71,10 @@ public class ApplymentApi extends AbstractApi {
|
|||||||
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
|
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
|
||||||
this.client().withType(WechatPayV3Type.ECOMMERCE_APPLYMENT, params).function((wechatPayV3Type, applymentParams) -> {
|
this.client().withType(WechatPayV3Type.ECOMMERCE_APPLYMENT, params).function((wechatPayV3Type, applymentParams) -> {
|
||||||
SignatureProvider signatureProvider = this.client().signatureProvider();
|
SignatureProvider signatureProvider = this.client().signatureProvider();
|
||||||
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
|
EcommerceApplymentParams applyRequestParams = this.convert(applymentParams, signatureProvider);
|
||||||
final X509Certificate x509Certificate = certificate.getX509Certificate();
|
|
||||||
EcommerceApplymentParams applyRequestParams = this.convert(applymentParams, signatureProvider, x509Certificate);
|
|
||||||
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA)).build().toUri();
|
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA)).build().toUri();
|
||||||
HttpHeaders httpHeaders = new HttpHeaders();
|
HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
|
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
|
||||||
return Post(uri, applyRequestParams, httpHeaders);
|
return Post(uri, applyRequestParams, httpHeaders);
|
||||||
}).consumer(wechatResponseEntity::convert).request();
|
}).consumer(wechatResponseEntity::convert).request();
|
||||||
return wechatResponseEntity;
|
return wechatResponseEntity;
|
||||||
@@ -138,50 +136,50 @@ public class ApplymentApi extends AbstractApi {
|
|||||||
return this.wechatPartnerSpecialMchApi.querySettlement(subMchid);
|
return this.wechatPartnerSpecialMchApi.querySettlement(subMchid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private EcommerceApplymentParams convert(EcommerceApplymentParams applymentParams, SignatureProvider signatureProvider, X509Certificate x509Certificate) {
|
private EcommerceApplymentParams convert(EcommerceApplymentParams applymentParams, SignatureProvider signatureProvider) {
|
||||||
EcommerceIdCardInfo idCardInfo = applymentParams.getIdCardInfo();
|
EcommerceIdCardInfo idCardInfo = applymentParams.getIdCardInfo();
|
||||||
if (idCardInfo != null) {
|
if (idCardInfo != null) {
|
||||||
idCardInfo.setIdCardName(signatureProvider.encryptRequestMessage(idCardInfo.getIdCardName(), x509Certificate));
|
idCardInfo.setIdCardName(signatureProvider.encryptRequestMessage(idCardInfo.getIdCardName(), this.wechatMetaBean()));
|
||||||
idCardInfo.setIdCardNumber(signatureProvider.encryptRequestMessage(idCardInfo.getIdCardNumber(), x509Certificate));
|
idCardInfo.setIdCardNumber(signatureProvider.encryptRequestMessage(idCardInfo.getIdCardNumber(), this.wechatMetaBean()));
|
||||||
String idCardAddress = idCardInfo.getIdCardAddress();
|
String idCardAddress = idCardInfo.getIdCardAddress();
|
||||||
if (StringUtils.hasText(idCardAddress)) {
|
if (StringUtils.hasText(idCardAddress)) {
|
||||||
idCardInfo.setIdCardAddress(signatureProvider.encryptRequestMessage(idCardAddress, x509Certificate));
|
idCardInfo.setIdCardAddress(signatureProvider.encryptRequestMessage(idCardAddress,this.wechatMetaBean()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EcommerceIdDocInfo idDocInfo = applymentParams.getIdDocInfo();
|
EcommerceIdDocInfo idDocInfo = applymentParams.getIdDocInfo();
|
||||||
if (idDocInfo != null) {
|
if (idDocInfo != null) {
|
||||||
idDocInfo.setIdDocName(signatureProvider.encryptRequestMessage(idDocInfo.getIdDocName(), x509Certificate));
|
idDocInfo.setIdDocName(signatureProvider.encryptRequestMessage(idDocInfo.getIdDocName(), this.wechatMetaBean()));
|
||||||
idDocInfo.setIdDocNumber(signatureProvider.encryptRequestMessage(idDocInfo.getIdDocNumber(), x509Certificate));
|
idDocInfo.setIdDocNumber(signatureProvider.encryptRequestMessage(idDocInfo.getIdDocNumber(), this.wechatMetaBean()));
|
||||||
String idDocAddress = idDocInfo.getIdDocAddress();
|
String idDocAddress = idDocInfo.getIdDocAddress();
|
||||||
if (StringUtils.hasText(idDocAddress)) {
|
if (StringUtils.hasText(idDocAddress)) {
|
||||||
idDocInfo.setIdDocAddress(signatureProvider.encryptRequestMessage(idDocAddress, x509Certificate));
|
idDocInfo.setIdDocAddress(signatureProvider.encryptRequestMessage(idDocAddress,this.wechatMetaBean()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UboInfo uboInfo = applymentParams.getUboInfo();
|
UboInfo uboInfo = applymentParams.getUboInfo();
|
||||||
if (uboInfo != null) {
|
if (uboInfo != null) {
|
||||||
UboInfo.IdCardInfo cardInfo = uboInfo.getIdCardInfo();
|
UboInfo.IdCardInfo cardInfo = uboInfo.getIdCardInfo();
|
||||||
if (cardInfo != null) {
|
if (cardInfo != null) {
|
||||||
cardInfo.setIdCardName(signatureProvider.encryptRequestMessage(cardInfo.getIdCardName(), x509Certificate));
|
cardInfo.setIdCardName(signatureProvider.encryptRequestMessage(cardInfo.getIdCardName(), this.wechatMetaBean()));
|
||||||
cardInfo.setIdCardNumber(signatureProvider.encryptRequestMessage(cardInfo.getIdCardNumber(), x509Certificate));
|
cardInfo.setIdCardNumber(signatureProvider.encryptRequestMessage(cardInfo.getIdCardNumber(), this.wechatMetaBean()));
|
||||||
}
|
}
|
||||||
UboInfo.IdDocInfo docInfo = uboInfo.getIdDocInfo();
|
UboInfo.IdDocInfo docInfo = uboInfo.getIdDocInfo();
|
||||||
if (docInfo != null) {
|
if (docInfo != null) {
|
||||||
docInfo.setIdDocName(signatureProvider.encryptRequestMessage(docInfo.getIdDocName(), x509Certificate));
|
docInfo.setIdDocName(signatureProvider.encryptRequestMessage(docInfo.getIdDocName(), this.wechatMetaBean()));
|
||||||
docInfo.setIdDocNumber(signatureProvider.encryptRequestMessage(docInfo.getIdDocNumber(), x509Certificate));
|
docInfo.setIdDocNumber(signatureProvider.encryptRequestMessage(docInfo.getIdDocNumber(), this.wechatMetaBean()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EcommerceAccountInfo accountInfo = applymentParams.getAccountInfo();
|
EcommerceAccountInfo accountInfo = applymentParams.getAccountInfo();
|
||||||
if (accountInfo != null) {
|
if (accountInfo != null) {
|
||||||
accountInfo.setAccountName(signatureProvider.encryptRequestMessage(accountInfo.getAccountName(), x509Certificate));
|
accountInfo.setAccountName(signatureProvider.encryptRequestMessage(accountInfo.getAccountName(), this.wechatMetaBean()));
|
||||||
accountInfo.setAccountNumber(signatureProvider.encryptRequestMessage(accountInfo.getAccountNumber(), x509Certificate));
|
accountInfo.setAccountNumber(signatureProvider.encryptRequestMessage(accountInfo.getAccountNumber(), this.wechatMetaBean()));
|
||||||
}
|
}
|
||||||
EcommerceContactInfo contactInfo = applymentParams.getContactInfo();
|
EcommerceContactInfo contactInfo = applymentParams.getContactInfo();
|
||||||
contactInfo.setContactName(signatureProvider.encryptRequestMessage(contactInfo.getContactName(), x509Certificate));
|
contactInfo.setContactName(signatureProvider.encryptRequestMessage(contactInfo.getContactName(), this.wechatMetaBean()));
|
||||||
contactInfo.setContactIdCardNumber(signatureProvider.encryptRequestMessage(contactInfo.getContactIdCardNumber(), x509Certificate));
|
contactInfo.setContactIdCardNumber(signatureProvider.encryptRequestMessage(contactInfo.getContactIdCardNumber(), this.wechatMetaBean()));
|
||||||
contactInfo.setMobilePhone(signatureProvider.encryptRequestMessage(contactInfo.getMobilePhone(), x509Certificate));
|
contactInfo.setMobilePhone(signatureProvider.encryptRequestMessage(contactInfo.getMobilePhone(), this.wechatMetaBean()));
|
||||||
String contactEmail = contactInfo.getContactEmail();
|
String contactEmail = contactInfo.getContactEmail();
|
||||||
if (contactEmail != null) {
|
if (contactEmail != null) {
|
||||||
contactInfo.setContactEmail(signatureProvider.encryptRequestMessage(contactEmail, x509Certificate));
|
contactInfo.setContactEmail(signatureProvider.encryptRequestMessage(contactEmail,this.wechatMetaBean()));
|
||||||
}
|
}
|
||||||
return applymentParams;
|
return applymentParams;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,15 +77,13 @@ public class ProfitsharingApi extends AbstractApi {
|
|||||||
.function((wechatPayV3Type, params) -> {
|
.function((wechatPayV3Type, params) -> {
|
||||||
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
|
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
|
||||||
SignatureProvider signatureProvider = this.client().signatureProvider();
|
SignatureProvider signatureProvider = this.client().signatureProvider();
|
||||||
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
|
|
||||||
final X509Certificate x509Certificate = certificate.getX509Certificate();
|
|
||||||
params.setAppid(v3.getAppId());
|
params.setAppid(v3.getAppId());
|
||||||
List<Receiver> receivers = params.getReceivers();
|
List<Receiver> receivers = params.getReceivers();
|
||||||
if (!CollectionUtils.isEmpty(receivers)) {
|
if (!CollectionUtils.isEmpty(receivers)) {
|
||||||
receivers.forEach(receiversItem -> {
|
receivers.forEach(receiversItem -> {
|
||||||
String name = receiversItem.getReceiverName();
|
String name = receiversItem.getReceiverName();
|
||||||
if (StringUtils.hasText(name)) {
|
if (StringUtils.hasText(name)) {
|
||||||
String encryptedName = signatureProvider.encryptRequestMessage(name, x509Certificate);
|
String encryptedName = signatureProvider.encryptRequestMessage(name,this.wechatMetaBean());
|
||||||
receiversItem.setReceiverName(encryptedName);
|
receiversItem.setReceiverName(encryptedName);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -94,7 +92,7 @@ public class ProfitsharingApi extends AbstractApi {
|
|||||||
.build()
|
.build()
|
||||||
.toUri();
|
.toUri();
|
||||||
HttpHeaders httpHeaders = new HttpHeaders();
|
HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
|
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
|
||||||
return Post(uri, params, httpHeaders);
|
return Post(uri, params, httpHeaders);
|
||||||
})
|
})
|
||||||
.consumer(wechatResponseEntity::convert)
|
.consumer(wechatResponseEntity::convert)
|
||||||
@@ -256,20 +254,17 @@ public class ProfitsharingApi extends AbstractApi {
|
|||||||
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
|
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
|
||||||
params.setAppid(v3.getAppId());
|
params.setAppid(v3.getAppId());
|
||||||
SignatureProvider signatureProvider = this.client().signatureProvider();
|
SignatureProvider signatureProvider = this.client().signatureProvider();
|
||||||
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
|
|
||||||
final X509Certificate x509Certificate = certificate.getX509Certificate();
|
|
||||||
|
|
||||||
String name = params.getName();
|
String name = params.getName();
|
||||||
if (ReceiverType.PERSONAL_OPENID.equals(params.getType()) && StringUtils.hasText(name)) {
|
if (ReceiverType.PERSONAL_OPENID.equals(params.getType()) && StringUtils.hasText(name)) {
|
||||||
// 个人应该必传
|
// 个人应该必传
|
||||||
String encryptedName = signatureProvider.encryptRequestMessage(name, x509Certificate);
|
String encryptedName = signatureProvider.encryptRequestMessage(name,this.wechatMetaBean());
|
||||||
params.setEncryptedName(encryptedName);
|
params.setEncryptedName(encryptedName);
|
||||||
}
|
}
|
||||||
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
|
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
|
||||||
.build()
|
.build()
|
||||||
.toUri();
|
.toUri();
|
||||||
HttpHeaders httpHeaders = new HttpHeaders();
|
HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
|
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
|
||||||
return Post(uri, params, httpHeaders);
|
return Post(uri, params, httpHeaders);
|
||||||
})
|
})
|
||||||
.consumer(wechatResponseEntity::convert)
|
.consumer(wechatResponseEntity::convert)
|
||||||
|
|||||||
@@ -38,4 +38,6 @@ public class Payer {
|
|||||||
* 用户子标识
|
* 用户子标识
|
||||||
*/
|
*/
|
||||||
private String subOpenid;
|
private String subOpenid;
|
||||||
|
|
||||||
|
private String authCode;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>payment-spring-boot-starter</artifactId>
|
<artifactId>payment-spring-boot-starter</artifactId>
|
||||||
<version>1.0.20.RELEASE</version>
|
<version>1.0.21.RELEASE</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|||||||
8
pom.xml
8
pom.xml
@@ -21,7 +21,7 @@
|
|||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<groupId>cn.felord</groupId>
|
<groupId>cn.felord</groupId>
|
||||||
<artifactId>payment-spring-boot</artifactId>
|
<artifactId>payment-spring-boot</artifactId>
|
||||||
<version>1.0.20.RELEASE</version>
|
<version>1.0.21.RELEASE</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
@@ -88,9 +88,9 @@
|
|||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
<java.version>1.8</java.version>
|
<java.version>1.8</java.version>
|
||||||
<spring-boot.version>2.7.7</spring-boot.version>
|
<spring-boot.version>2.7.18</spring-boot.version>
|
||||||
<alipay-sdk.version>4.31.7.ALL</alipay-sdk.version>
|
<alipay-sdk.version>4.40.251.ALL</alipay-sdk.version>
|
||||||
<bcprov.version>1.74</bcprov.version>
|
<bcprov.version>1.78</bcprov.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<distributionManagement>
|
<distributionManagement>
|
||||||
|
|||||||
Reference in New Issue
Block a user