优化默认的证书加载,增加缓存

This commit is contained in:
xiafang
2023-05-22 14:07:24 +08:00
parent da0fe928eb
commit 85fde9bb68
3 changed files with 47 additions and 52 deletions

View File

@@ -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;
} }
} }

View File

@@ -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());
}
} }

View File

@@ -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());
} }
} }