diff --git a/README.md b/README.md
index 1d7c7df..c24ba4f 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@
cn.felord
payment-spring-boot-starter
- 1.0.11.RELEASE
+ 1.0.12.RELEASE
```
diff --git a/docs/README.md b/docs/README.md
index 2e5d488..c5c7126 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -35,7 +35,7 @@
cn.felord
payment-spring-boot-starter
- 1.0.11.RELEASE
+ 1.0.12.RELEASE
```
## 采用技术
diff --git a/docs/changelog.md b/docs/changelog.md
index 73f06ad..232e929 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -1,3 +1,10 @@
+## 1.0.12.RELEASE
+- 微信支付
+ - fix: 修复多租户配置下,平台证书刷新错误的问题([#49](https://github.com/NotFound403/payment-spring-boot/issues/49))
+ - fix: 分账API描述符错误([#48](https://github.com/NotFound403/payment-spring-boot/issues/48)) 。
+ - refactor: 避免受jackson类库xml模块的影响
+ - refactor: V2签名优化
+
## 1.0.11.RELEASE
- 微信支付
@@ -13,7 +20,7 @@
- fix: 修复查询代金券参数的错误
- 支付宝
- feat: 支付宝增加字段`classpathUsed`来标识是否使用类路径,默认`true`。证书路径可依此来决定是使用绝对路径还是类路径
-
+
## 1.0.10.RELEASE
- 微信支付
diff --git a/docs/quick_start.md b/docs/quick_start.md
index c61df5f..43b0a51 100644
--- a/docs/quick_start.md
+++ b/docs/quick_start.md
@@ -4,7 +4,7 @@
cn.felord
payment-spring-boot-starter
- 1.0.11.RELEASE
+ 1.0.12.RELEASE
```
> 基于 **Spring Boot 2.x**
diff --git a/payment-spring-boot-autoconfigure/pom.xml b/payment-spring-boot-autoconfigure/pom.xml
index 83fb1c6..8585112 100644
--- a/payment-spring-boot-autoconfigure/pom.xml
+++ b/payment-spring-boot-autoconfigure/pom.xml
@@ -5,11 +5,11 @@
cn.felord
payment-spring-boot
- 1.0.11.RELEASE
+ 1.0.12.RELEASE
payment-spring-boot-autoconfigure
- 1.0.11.RELEASE
+ 1.0.12.RELEASE
jar
4.0.0
diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/WechatPayV3Type.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/WechatPayV3Type.java
index 654ef68..52528e2 100644
--- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/WechatPayV3Type.java
+++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/WechatPayV3Type.java
@@ -622,7 +622,7 @@ public enum WechatPayV3Type {
*
* @since 1.0.11.RELEASE
*/
- PROFITSHARING_RECEIVERS_DELETE(HttpMethod.POST, "%s/v3/profitsharing/receivers/add");
+ PROFITSHARING_RECEIVERS_DELETE(HttpMethod.POST, "%s/v3/profitsharing/receivers/delete");
/**
* The Pattern.
*
diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v2/model/BaseModel.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v2/model/BaseModel.java
index 1f6380f..e115e7b 100644
--- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v2/model/BaseModel.java
+++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v2/model/BaseModel.java
@@ -21,8 +21,8 @@ package cn.felord.payment.wechat.v2.model;
import cn.felord.payment.PayException;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
@@ -56,6 +56,8 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.CertificateException;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
/**
* The type Base model.
@@ -74,7 +76,8 @@ public abstract class BaseModel {
XML_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL)
// 属性使用 驼峰首字母小写
.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
- OBJECT_MAPPER.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
+ OBJECT_MAPPER
+// .configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
}
@@ -149,10 +152,11 @@ public abstract class BaseModel {
*/
@SneakyThrows
private String hmacSha256(String src) {
- Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
- SecretKeySpec secret_key = new SecretKeySpec(appSecret.getBytes(),"HmacSHA256");
- sha256_HMAC.init(secret_key);
- byte[] bytes = sha256_HMAC.doFinal(src.getBytes(StandardCharsets.UTF_8));
+ String algorithm = "HmacSHA256";
+ Mac sha256HMAC = Mac.getInstance(algorithm,"BC");
+ SecretKeySpec secretKeySpec = new SecretKeySpec(appSecret.getBytes(), algorithm);
+ sha256HMAC.init(secretKeySpec);
+ byte[] bytes = sha256HMAC.doFinal(src.getBytes(StandardCharsets.UTF_8));
return Hex.toHexString(bytes).toUpperCase();
}
@@ -166,13 +170,17 @@ public abstract class BaseModel {
@SneakyThrows
private String link(T t) {
Assert.hasText(appSecret, "wechat pay appSecret is required");
- String link = OBJECT_MAPPER
- .writer()
- .writeValueAsString(t)
- .replaceAll("\":\"", "=")
- .replaceAll("\",\"", "&")
- .replaceAll("\\\\\"", "\"");
- return link.substring(2, link.length() - 2).concat("&key=").concat(this.appSecret);
+ String json = OBJECT_MAPPER
+ .writeValueAsString(t);
+
+ TreeMap map = OBJECT_MAPPER.readValue(json, new TypeReference>() {
+ });
+
+ String query = map.entrySet()
+ .stream()
+ .map(entry -> entry.getKey().concat("=").concat(entry.getValue()))
+ .collect(Collectors.joining("&"));
+ return query.concat("&key=").concat(this.appSecret);
}
diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/SignatureProvider.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/SignatureProvider.java
index f3af733..e4f034d 100644
--- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/SignatureProvider.java
+++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/SignatureProvider.java
@@ -30,7 +30,12 @@ import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.http.*;
-import org.springframework.util.*;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
+import org.springframework.util.AlternativeJdkIdGenerator;
+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.RestTemplate;
import org.springframework.web.util.UriComponents;
@@ -49,10 +54,7 @@ import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Objects;
+import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@@ -86,7 +88,7 @@ public class SignatureProvider {
/**
* 微信平台证书容器 key = 序列号 value = 证书对象
*/
- private static final Map CERTIFICATE_MAP = new ConcurrentHashMap<>();
+ private static final Map CERTIFICATE_MAP = new ConcurrentHashMap<>();
/**
* 加密算法提供方 - BouncyCastle
*/
@@ -96,7 +98,7 @@ public class SignatureProvider {
/**
* The Rest operations.
*/
- private final RestOperations restOperations = new RestTemplate();
+ private final RestOperations restOperations;
/**
* The Wechat meta container.
*/
@@ -110,6 +112,11 @@ public class SignatureProvider {
public SignatureProvider(WechatMetaContainer wechatMetaContainer) {
Provider bouncyCastleProvider = new BouncyCastleProvider();
Security.addProvider(bouncyCastleProvider);
+ RestTemplate restOperations = new RestTemplate();
+ List> messageConverters = restOperations.getMessageConverters();
+ messageConverters.removeIf(httpMessageConverter -> httpMessageConverter instanceof MappingJackson2XmlHttpMessageConverter);
+ restOperations.setMessageConverters(messageConverters);
+ this.restOperations = restOperations;
this.wechatMetaContainer = wechatMetaContainer;
wechatMetaContainer.getTenantIds().forEach(this::refreshCertificate);
}
@@ -174,10 +181,10 @@ public class SignatureProvider {
if (CERTIFICATE_MAP.isEmpty() || !CERTIFICATE_MAP.containsKey(wechatpaySerial)) {
wechatMetaContainer.getTenantIds().forEach(this::refreshCertificate);
}
- Certificate certificate = CERTIFICATE_MAP.get(wechatpaySerial);
+ Certificate certificate = CERTIFICATE_MAP.get(wechatpaySerial).getX509Certificate();
final String signatureStr = createSign(true, params.getWechatpayTimestamp(), params.getWechatpayNonce(), params.getBody());
- Signature signer = Signature.getInstance("SHA256withRSA");
+ Signature signer = Signature.getInstance("SHA256withRSA", BC_PROVIDER);
signer.initVerify(certificate);
signer.update(signatureStr.getBytes(StandardCharsets.UTF_8));
@@ -234,7 +241,11 @@ public class SignatureProvider {
try {
Certificate certificate = certificateFactory.generateCertificate(inputStream);
String responseSerialNo = objectNode.get("serial_no").asText();
- CERTIFICATE_MAP.put(responseSerialNo, certificate);
+ X509WechatCertificateInfo x509WechatCertificateInfo = new X509WechatCertificateInfo();
+ x509WechatCertificateInfo.setWechatPaySerial(responseSerialNo);
+ x509WechatCertificateInfo.setTenantId(tenantId);
+ x509WechatCertificateInfo.setX509Certificate((X509Certificate) certificate);
+ CERTIFICATE_MAP.put(responseSerialNo, x509WechatCertificateInfo);
} catch (CertificateException e) {
throw new PayException("An error occurred while generating the wechat v3 certificate, reason : " + e.getMessage());
}
@@ -307,21 +318,23 @@ public class SignatureProvider {
/**
* Get certificate x 509 wechat certificate info.
*
+ * @param tenantId the tenant id
* @return the x 509 wechat certificate info
*/
- public X509WechatCertificateInfo getCertificate() {
+ public X509WechatCertificateInfo getCertificate(String tenantId) {
for (String serial : CERTIFICATE_MAP.keySet()) {
- X509Certificate x509Cert = (X509Certificate) CERTIFICATE_MAP.get(serial);
- try {
- x509Cert.checkValidity();
- X509WechatCertificateInfo x509WechatCertificateInfo = new X509WechatCertificateInfo();
- x509WechatCertificateInfo.setWechatPaySerial(serial);
- x509WechatCertificateInfo.setX509Certificate(x509Cert);
- return x509WechatCertificateInfo;
- } catch (Exception e) {
- log.warn("the wechat certificate is invalid , {}", e.getMessage());
- // Async?
- wechatMetaContainer.getTenantIds().forEach(this::refreshCertificate);
+ X509WechatCertificateInfo wechatCertificateInfo = CERTIFICATE_MAP.get(serial);
+ X509Certificate x509Cert = wechatCertificateInfo.getX509Certificate();
+ if (wechatCertificateInfo.getTenantId().equals(tenantId)){
+ try {
+ x509Cert.checkValidity();
+
+ return wechatCertificateInfo;
+ } catch (Exception e) {
+ log.warn("the wechat certificate is invalid , {}", e.getMessage());
+ // Async?
+ wechatMetaContainer.getTenantIds().forEach(this::refreshCertificate);
+ }
}
}
throw new PayException("failed to obtain wechat pay x509Certificate ");
diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatBatchTransferApi.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatBatchTransferApi.java
index 198586a..8484ed3 100644
--- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatBatchTransferApi.java
+++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatBatchTransferApi.java
@@ -77,7 +77,7 @@ public class WechatBatchTransferApi extends AbstractApi {
List transferDetailList = createBatchTransferParams.getTransferDetailList();
SignatureProvider signatureProvider = this.client().signatureProvider();
- X509WechatCertificateInfo certificate = signatureProvider.getCertificate();
+ X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
List encrypted = transferDetailList.stream()
.peek(transferDetailListItem -> {
diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatPartnerProfitsharingApi.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatPartnerProfitsharingApi.java
index 3504cf5..08d9be5 100644
--- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatPartnerProfitsharingApi.java
+++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatPartnerProfitsharingApi.java
@@ -56,7 +56,7 @@ public class WechatPartnerProfitsharingApi extends AbstractApi {
.function((wechatPayV3Type, params) -> {
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
SignatureProvider signatureProvider = this.client().signatureProvider();
- X509WechatCertificateInfo certificate = signatureProvider.getCertificate();
+ X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
params.setAppid(v3.getAppId());
List receivers = params.getReceivers();
@@ -272,7 +272,7 @@ public class WechatPartnerProfitsharingApi extends AbstractApi {
.function((wechatPayV3Type, params) -> {
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
SignatureProvider signatureProvider = this.client().signatureProvider();
- X509WechatCertificateInfo certificate = signatureProvider.getCertificate();
+ X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
params.setAppid(v3.getAppId());
String name = params.getName();
diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatPayClient.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatPayClient.java
index fb69c71..deab527 100644
--- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatPayClient.java
+++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatPayClient.java
@@ -29,6 +29,7 @@ import org.springframework.http.*;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
+import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.util.Assert;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestOperations;
@@ -351,7 +352,7 @@ public class WechatPayClient {
DefaultResponseErrorHandler errorHandler = new WechatPayResponseErrorHandler();
restTemplate.setErrorHandler(errorHandler);
List> messageConverters = restTemplate.getMessageConverters();
-
+ messageConverters.removeIf(httpMessageConverter -> httpMessageConverter instanceof MappingJackson2XmlHttpMessageConverter);
messageConverters.removeIf(httpMessageConverter -> httpMessageConverter instanceof AllEncompassingFormHttpMessageConverter);
messageConverters.add(new ExtensionFormHttpMessageConverter());
restTemplate.setMessageConverters(messageConverters);
diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatProfitsharingApi.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatProfitsharingApi.java
index 3158ae6..3f3c0f0 100644
--- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatProfitsharingApi.java
+++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatProfitsharingApi.java
@@ -53,7 +53,7 @@ public class WechatProfitsharingApi extends AbstractApi {
.function((wechatPayV3Type, params) -> {
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
SignatureProvider signatureProvider = this.client().signatureProvider();
- X509WechatCertificateInfo certificate = signatureProvider.getCertificate();
+ X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
params.setAppid(v3.getAppId());
List receivers = params.getReceivers();
@@ -239,7 +239,7 @@ public class WechatProfitsharingApi extends AbstractApi {
.function((wechatPayV3Type, params) -> {
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
SignatureProvider signatureProvider = this.client().signatureProvider();
- X509WechatCertificateInfo certificate = signatureProvider.getCertificate();
+ X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
params.setAppid(v3.getAppId());
String name = params.getName();
diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/X509WechatCertificateInfo.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/X509WechatCertificateInfo.java
index 7d62e5e..9604e7a 100644
--- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/X509WechatCertificateInfo.java
+++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/X509WechatCertificateInfo.java
@@ -33,6 +33,10 @@ public class X509WechatCertificateInfo {
* wechatPaySerial
*/
private String wechatPaySerial;
+ /**
+ * tenantId
+ */
+ private String tenantId;
/**
* X509Certificate
*/
diff --git a/payment-spring-boot-starter/pom.xml b/payment-spring-boot-starter/pom.xml
index 6e742a5..eb718bf 100644
--- a/payment-spring-boot-starter/pom.xml
+++ b/payment-spring-boot-starter/pom.xml
@@ -5,11 +5,11 @@
cn.felord
payment-spring-boot
- 1.0.11.RELEASE
+ 1.0.12.RELEASE
payment-spring-boot-starter
- 1.0.11.RELEASE
+ 1.0.12.RELEASE
jar
4.0.0
diff --git a/pom.xml b/pom.xml
index f827c72..0193578 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
cn.felord
payment-spring-boot
- 1.0.11.RELEASE
+ 1.0.12.RELEASE
pom
4.0.0