From 6534d4c0f66f89ac08a67ed18c53e235b6b68364 Mon Sep 17 00:00:00 2001 From: xiafang Date: Fri, 3 Feb 2023 13:32:00 +0800 Subject: [PATCH] =?UTF-8?q?enhance:=20=E5=A2=9E=E5=8A=A0=E6=8A=BD=E8=B1=A1?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3WechatTenantService=E8=B4=9F=E8=B4=A3?= =?UTF-8?q?=E4=BB=8E=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6=E6=88=96=E8=80=85?= =?UTF-8?q?=E5=85=B6=E5=AE=83=E6=95=B0=E6=8D=AE=E6=BA=90=E6=A3=80=E7=B4=A2?= =?UTF-8?q?=E7=A7=9F=E6=88=B7=E9=85=8D=E7=BD=AE=E4=BF=A1=E6=81=AF=EF=BC=8C?= =?UTF-8?q?=E6=8F=90=E4=BE=9B=E9=BB=98=E8=AE=A4=E5=AE=9E=E7=8E=B0InMemoryW?= =?UTF-8?q?echatTenantService=EF=BC=88=E5=8F=AF=E8=A2=AB=E8=A6=86=E7=9B=96?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #88 --- .../wechat/InMemoryWechatTenantService.java | 60 +++++++++++++++++++ .../wechat/WechatPayConfiguration.java | 38 +++--------- .../payment/wechat/WechatTenantService.java | 30 ++++++++++ .../WechatTenantServiceConfiguration.java | 48 +++++++++++++++ .../payment/wechat/v3/KeyPairFactory.java | 27 +++++---- .../payment/wechat/v3/SignatureProvider.java | 10 ++-- .../wechat/v3/WechatMetaContainer.java | 24 +++++--- 7 files changed, 181 insertions(+), 56 deletions(-) create mode 100644 payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/InMemoryWechatTenantService.java create mode 100644 payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/WechatTenantService.java create mode 100644 payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/WechatTenantServiceConfiguration.java diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/InMemoryWechatTenantService.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/InMemoryWechatTenantService.java new file mode 100644 index 0000000..aa2af98 --- /dev/null +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/InMemoryWechatTenantService.java @@ -0,0 +1,60 @@ +/* + * Copyright 2019-2022 felord.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * Website: + * https://felord.cn + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.felord.payment.wechat; + +import cn.felord.payment.wechat.v3.KeyPairFactory; +import cn.felord.payment.wechat.v3.WechatMetaBean; +import lombok.AllArgsConstructor; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; + +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author xiafang + * @since 2023/2/3 11:40 + */ +@AllArgsConstructor +public class InMemoryWechatTenantService implements WechatTenantService { + private final WechatPayProperties wechatPayProperties; + + @Override + public Set getAllTenants() { + Map v3Map = wechatPayProperties.getV3(); + KeyPairFactory keyPairFactory = new KeyPairFactory(); + return v3Map.entrySet() + .stream() + .map(entry -> { + WechatPayProperties.V3 v3 = entry.getValue(); + String tenantId = entry.getKey(); + String certPath = v3.getCertPath(); + String certAbsolutePath = v3.getCertAbsolutePath(); + String mchId = v3.getMchId(); + Resource resource = certAbsolutePath != null ? new FileSystemResource(certAbsolutePath) : + new ClassPathResource(certPath == null ? "wechat/apiclient_cert.p12" : certPath); + WechatMetaBean wechatMetaBean = keyPairFactory.initWechatMetaBean(resource, mchId); + wechatMetaBean.setV3(v3); + wechatMetaBean.setTenantId(tenantId); + return wechatMetaBean; + }) + .collect(Collectors.toSet()); + } +} diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/WechatPayConfiguration.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/WechatPayConfiguration.java index be33287..73d19d6 100644 --- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/WechatPayConfiguration.java +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/WechatPayConfiguration.java @@ -17,17 +17,13 @@ package cn.felord.payment.wechat; -import cn.felord.payment.wechat.v3.*; +import cn.felord.payment.wechat.v3.SignatureProvider; +import cn.felord.payment.wechat.v3.WechatApiProvider; +import cn.felord.payment.wechat.v3.WechatMetaContainer; +import cn.felord.payment.wechat.v3.WechatPayClient; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; - -import java.util.Map; /** * The type Wechat pay configuration. @@ -36,39 +32,19 @@ import java.util.Map; * @since 1.0.0.RELEASE */ @Configuration(proxyBeanMethods = false) -@Conditional(WechatPayConfiguredCondition.class) -@EnableConfigurationProperties(WechatPayProperties.class) public class WechatPayConfiguration { - /** - * The constant CERT_ALIAS. - */ - private static final String CERT_ALIAS = "Tenpay Certificate"; /** * 微信支付公私钥 以及序列号等元数据. * - * @param wechatPayProperties the wechat pay properties + * @param wechatTenantService the wechat tenant service * @return the wechat cert bean */ @Bean @ConditionalOnMissingBean - WechatMetaContainer wechatMetaContainer(WechatPayProperties wechatPayProperties) { - - Map v3Map = wechatPayProperties.getV3(); + WechatMetaContainer wechatMetaContainer(WechatTenantService wechatTenantService) { WechatMetaContainer container = new WechatMetaContainer(); - KeyPairFactory keyPairFactory = new KeyPairFactory(); - v3Map.keySet().forEach(tenantId -> { - WechatPayProperties.V3 v3 = v3Map.get(tenantId); - String certPath = v3.getCertPath(); - String certAbsolutePath = v3.getCertAbsolutePath(); - String mchId = v3.getMchId(); - Resource resource = certAbsolutePath != null ? new FileSystemResource(certAbsolutePath) : - new ClassPathResource(certPath == null ? "wechat/apiclient_cert.p12" : certPath); - WechatMetaBean wechatMetaBean = keyPairFactory.initWechatMetaBean(resource, CERT_ALIAS, mchId); - wechatMetaBean.setV3(v3); - wechatMetaBean.setTenantId(tenantId); - container.addWechatMeta(tenantId, wechatMetaBean); - }); + container.addWechatMetas(wechatTenantService.getAllTenants()); return container; } diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/WechatTenantService.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/WechatTenantService.java new file mode 100644 index 0000000..8269096 --- /dev/null +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/WechatTenantService.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2022 felord.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * Website: + * https://felord.cn + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.felord.payment.wechat; + +import cn.felord.payment.wechat.v3.WechatMetaBean; + +import java.util.Set; + +/** + * @author xiafang + * @since 2023/2/3 11:37 + */ +public interface WechatTenantService { + Set getAllTenants(); +} diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/WechatTenantServiceConfiguration.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/WechatTenantServiceConfiguration.java new file mode 100644 index 0000000..f3bf990 --- /dev/null +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/WechatTenantServiceConfiguration.java @@ -0,0 +1,48 @@ +/* + * Copyright 2019-2022 felord.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * Website: + * https://felord.cn + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.felord.payment.wechat; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; + +/** + * The type Wechat tenant service configuration. + * + * @author xiafang + * @since 2023 /2/3 12:32 + */ +@Configuration(proxyBeanMethods = false) +@Conditional(WechatPayConfiguredCondition.class) +@EnableConfigurationProperties(WechatPayProperties.class) +public class WechatTenantServiceConfiguration { + + /** + * Wechat tenant service wechat tenant service. + * + * @param wechatPayProperties the wechat pay properties + * @return the wechat tenant service + */ + @Bean + @ConditionalOnMissingBean + public WechatTenantService wechatTenantService(WechatPayProperties wechatPayProperties) { + return new InMemoryWechatTenantService(wechatPayProperties); + } +} diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/KeyPairFactory.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/KeyPairFactory.java index a1ad6db..255abc8 100644 --- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/KeyPairFactory.java +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/KeyPairFactory.java @@ -18,11 +18,13 @@ package cn.felord.payment.wechat.v3; import cn.felord.payment.PayException; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; -import java.security.*; +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.PrivateKey; +import java.security.PublicKey; import java.security.cert.X509Certificate; /** @@ -32,17 +34,20 @@ import java.security.cert.X509Certificate; * @since 1.0.0.RELEASE */ public class KeyPairFactory { - + private static final String CERT_ALIAS = "Tenpay Certificate"; private static final KeyStore PKCS12_KEY_STORE; - static { - try { - PKCS12_KEY_STORE = KeyStore.getInstance("PKCS12"); - } catch (KeyStoreException e) { - throw new PayException(" wechat pay keystore initialization failed"); - } - } + static { + try { + PKCS12_KEY_STORE = KeyStore.getInstance("PKCS12"); + } catch (KeyStoreException e) { + throw new PayException(" wechat pay keystore initialization failed"); + } + } + public WechatMetaBean initWechatMetaBean(Resource resource, String keyPass) { + return this.initWechatMetaBean(resource, CERT_ALIAS, keyPass); + } /** * 获取公私钥. 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 f0c1a5a..2a88ef8 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 @@ -187,7 +187,7 @@ public class SignatureProvider { return CERTIFICATE_SET.stream() .filter(cert -> Objects.equals(wechatpaySerial, cert.getWechatPaySerial())) .findAny() - .orElseThrow(()->new PayException("cannot obtain the certificate")); + .orElseThrow(() -> new PayException("cannot obtain the certificate")); }); @@ -235,8 +235,8 @@ public class SignatureProvider { } ArrayNode certificates = bodyObjectNode.withArray("data"); if (certificates.isArray() && certificates.size() > 0) { - CERTIFICATE_SET.forEach( x509WechatCertificateInfo -> { - if (Objects.equals(tenantId,x509WechatCertificateInfo.getTenantId())){ + CERTIFICATE_SET.forEach(x509WechatCertificateInfo -> { + if (Objects.equals(tenantId, x509WechatCertificateInfo.getTenantId())) { CERTIFICATE_SET.remove(x509WechatCertificateInfo); } }); @@ -257,7 +257,7 @@ public class SignatureProvider { x509WechatCertificateInfo.setWechatPaySerial(responseSerialNo); x509WechatCertificateInfo.setTenantId(tenantId); x509WechatCertificateInfo.setX509Certificate((X509Certificate) certificate); - CERTIFICATE_SET.add( x509WechatCertificateInfo); + CERTIFICATE_SET.add(x509WechatCertificateInfo); } catch (CertificateException e) { throw new PayException("An error occurred while generating the wechat v3 certificate, reason : " + e.getMessage()); } @@ -359,7 +359,7 @@ public class SignatureProvider { */ public X509WechatCertificateInfo getCertificate(String tenantId) { - return CERTIFICATE_SET.stream() + return CERTIFICATE_SET.stream() .filter(cert -> Objects.equals(tenantId, cert.getTenantId())) .findAny() .orElseGet(() -> { diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatMetaContainer.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatMetaContainer.java index fe988e6..5109bec 100644 --- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatMetaContainer.java +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatMetaContainer.java @@ -18,6 +18,8 @@ package cn.felord.payment.wechat.v3; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentSkipListSet; /** * 配置容器 @@ -26,22 +28,26 @@ import java.util.*; * @since 1.0.0.RELEASE */ public class WechatMetaContainer { - private final Map wechatMetaBeanMap = new HashMap<>(); - private final Set tenantIds = new HashSet<>(); + private final Map wechatMetaBeanMap = new ConcurrentHashMap<>(); + private final Set tenantIds = new ConcurrentSkipListSet<>(); /** - * Add wechat meta boolean. + * Add wechat metas. * - * @param tenantId the tenantId - * @param wechatMetaBean the wechat meta bean - * @return the boolean + * @param wechatMetaBeans the wechat meta beans */ - public WechatMetaBean addWechatMeta(String tenantId, WechatMetaBean wechatMetaBean) { - tenantIds.add(tenantId); - return this.wechatMetaBeanMap.put(tenantId, wechatMetaBean); + public void addWechatMetas(Collection wechatMetaBeans) { + wechatMetaBeans.forEach(this::addMeta); } + private void addMeta(WechatMetaBean wechatMetaBean) { + String tenantId = wechatMetaBean.getTenantId(); + tenantIds.add(tenantId); + wechatMetaBeanMap.put(tenantId, wechatMetaBean); + } + + /** * Remove wechat meta wechat meta bean. *