mirror of
https://github.com/dromara/payment-spring-boot.git
synced 2026-03-13 21:33:41 +08:00
优化默认的证书加载,增加缓存
This commit is contained in:
@@ -23,8 +23,10 @@ import lombok.AllArgsConstructor;
|
|||||||
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.ResourceUtils;
|
import org.springframework.util.ResourceUtils;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -39,27 +41,32 @@ import java.util.stream.Collectors;
|
|||||||
public class InMemoryWechatTenantService implements WechatTenantService {
|
public class InMemoryWechatTenantService implements WechatTenantService {
|
||||||
private final WechatPayProperties wechatPayProperties;
|
private final WechatPayProperties wechatPayProperties;
|
||||||
private final ResourceLoader resourceLoader;
|
private final ResourceLoader resourceLoader;
|
||||||
|
private final Set<WechatMetaBean> cache = new HashSet<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<WechatMetaBean> loadTenants() {
|
public Set<WechatMetaBean> loadTenants() {
|
||||||
Map<String, WechatPayProperties.V3> v3Map = wechatPayProperties.getV3();
|
if (CollectionUtils.isEmpty(cache)) {
|
||||||
KeyPairFactory keyPairFactory = new KeyPairFactory();
|
Map<String, WechatPayProperties.V3> v3Map = wechatPayProperties.getV3();
|
||||||
return v3Map.entrySet()
|
KeyPairFactory keyPairFactory = new KeyPairFactory();
|
||||||
.stream()
|
Set<WechatMetaBean> beans = v3Map.entrySet()
|
||||||
.map(entry -> {
|
.stream()
|
||||||
WechatPayProperties.V3 v3 = entry.getValue();
|
.map(entry -> {
|
||||||
String tenantId = entry.getKey();
|
WechatPayProperties.V3 v3 = entry.getValue();
|
||||||
String certPath = v3.getCertPath();
|
String tenantId = entry.getKey();
|
||||||
String certAbsolutePath = v3.getCertAbsolutePath();
|
String certPath = v3.getCertPath();
|
||||||
String mchId = v3.getMchId();
|
String certAbsolutePath = v3.getCertAbsolutePath();
|
||||||
Resource resource = certAbsolutePath != null ? new FileSystemResource(certAbsolutePath) :
|
String mchId = v3.getMchId();
|
||||||
resourceLoader.getResource(certPath == null ? "classpath:wechat/apiclient_cert.p12" :
|
Resource resource = certAbsolutePath != null ? new FileSystemResource(certAbsolutePath) :
|
||||||
certPath.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX) ? certPath : ResourceUtils.CLASSPATH_URL_PREFIX + certPath);
|
resourceLoader.getResource(certPath == null ? "classpath:wechat/apiclient_cert.p12" :
|
||||||
WechatMetaBean wechatMetaBean = keyPairFactory.initWechatMetaBean(resource, mchId);
|
certPath.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX) ? certPath : ResourceUtils.CLASSPATH_URL_PREFIX + certPath);
|
||||||
wechatMetaBean.setV3(v3);
|
WechatMetaBean wechatMetaBean = keyPairFactory.initWechatMetaBean(resource, mchId);
|
||||||
wechatMetaBean.setTenantId(tenantId);
|
wechatMetaBean.setV3(v3);
|
||||||
return wechatMetaBean;
|
wechatMetaBean.setTenantId(tenantId);
|
||||||
})
|
return wechatMetaBean;
|
||||||
.collect(Collectors.toSet());
|
})
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
cache.addAll(beans);
|
||||||
|
}
|
||||||
|
return cache;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,11 +27,7 @@ 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.springframework.http.HttpHeaders;
|
import org.springframework.http.*;
|
||||||
import org.springframework.http.HttpMethod;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.http.RequestEntity;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
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.AlternativeJdkIdGenerator;
|
||||||
@@ -54,8 +50,7 @@ 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.time.LocalDateTime;
|
import java.time.Instant;
|
||||||
import java.time.ZoneOffset;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -135,7 +130,7 @@ public class SignatureProvider {
|
|||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public String requestSign(String tenantId, String method, String canonicalUrl, String body) {
|
public String requestSign(String tenantId, String method, String canonicalUrl, String body) {
|
||||||
|
|
||||||
long timestamp = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
|
long timestamp = Instant.now().getEpochSecond();
|
||||||
String nonceStr = nonceStrGenerator.generateId()
|
String nonceStr = nonceStrGenerator.generateId()
|
||||||
.toString()
|
.toString()
|
||||||
.replaceAll("-", "");
|
.replaceAll("-", "");
|
||||||
@@ -175,7 +170,6 @@ public class SignatureProvider {
|
|||||||
* @param params the params
|
* @param params the params
|
||||||
* @return the boolean
|
* @return the boolean
|
||||||
*/
|
*/
|
||||||
@SneakyThrows
|
|
||||||
public boolean responseSignVerify(ResponseSignVerifyParams params) {
|
public boolean responseSignVerify(ResponseSignVerifyParams params) {
|
||||||
|
|
||||||
String wechatpaySerial = params.getWechatpaySerial();
|
String wechatpaySerial = params.getWechatpaySerial();
|
||||||
@@ -190,13 +184,15 @@ public class SignatureProvider {
|
|||||||
.orElseThrow(() -> new PayException("cannot obtain the certificate"));
|
.orElseThrow(() -> new PayException("cannot obtain the certificate"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
final String signatureStr = createSign(params.getWechatpayTimestamp(), params.getWechatpayNonce(), params.getBody());
|
final String signatureStr = createSign(params.getWechatpayTimestamp(), params.getWechatpayNonce(), params.getBody());
|
||||||
Signature signer = Signature.getInstance("SHA256withRSA", BC_PROVIDER);
|
Signature signer = Signature.getInstance("SHA256withRSA", BC_PROVIDER);
|
||||||
signer.initVerify(certificate.getX509Certificate());
|
signer.initVerify(certificate.getX509Certificate());
|
||||||
signer.update(signatureStr.getBytes(StandardCharsets.UTF_8));
|
signer.update(signatureStr.getBytes(StandardCharsets.UTF_8));
|
||||||
|
return signer.verify(Base64Utils.decodeFromString(params.getWechatpaySignature()));
|
||||||
return signer.verify(Base64Utils.decodeFromString(params.getWechatpaySignature()));
|
}catch (Exception e){
|
||||||
|
throw new PayException("An exception occurred during the response verification, the cause: "+e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,12 @@ package cn.felord.payment.wechat.v3;
|
|||||||
import cn.felord.payment.wechat.WechatTenantService;
|
import cn.felord.payment.wechat.WechatTenantService;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentSkipListSet;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 配置容器
|
* 配置容器
|
||||||
@@ -33,7 +36,6 @@ import java.util.concurrent.ConcurrentSkipListSet;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class WechatMetaContainer {
|
public class WechatMetaContainer {
|
||||||
private final Map<String, WechatMetaBean> wechatMetaBeanMap = new ConcurrentHashMap<>();
|
private final Map<String, WechatMetaBean> wechatMetaBeanMap = new ConcurrentHashMap<>();
|
||||||
private final Set<String> tenantIds = new ConcurrentSkipListSet<>();
|
|
||||||
private final WechatTenantService wechatTenantService;
|
private final WechatTenantService wechatTenantService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,22 +49,9 @@ public class WechatMetaContainer {
|
|||||||
|
|
||||||
private void addMeta(WechatMetaBean wechatMetaBean) {
|
private void addMeta(WechatMetaBean wechatMetaBean) {
|
||||||
String tenantId = wechatMetaBean.getTenantId();
|
String tenantId = wechatMetaBean.getTenantId();
|
||||||
tenantIds.add(tenantId);
|
|
||||||
wechatMetaBeanMap.put(tenantId, wechatMetaBean);
|
wechatMetaBeanMap.put(tenantId, wechatMetaBean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove wechat meta wechat meta bean.
|
|
||||||
*
|
|
||||||
* @param tenantId the tenantId
|
|
||||||
* @return the wechat meta bean
|
|
||||||
*/
|
|
||||||
public WechatMetaBean removeWechatMeta(String tenantId) {
|
|
||||||
tenantIds.remove(tenantId);
|
|
||||||
return this.wechatMetaBeanMap.remove(tenantId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets wechat meta.
|
* Gets wechat meta.
|
||||||
*
|
*
|
||||||
@@ -86,6 +75,9 @@ public class WechatMetaContainer {
|
|||||||
* @return the properties keys
|
* @return the properties keys
|
||||||
*/
|
*/
|
||||||
public Set<String> getTenantIds() {
|
public Set<String> getTenantIds() {
|
||||||
return tenantIds;
|
return wechatTenantService.loadTenants()
|
||||||
|
.stream()
|
||||||
|
.map(WechatMetaBean::getTenantId)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user