mirror of
https://github.com/dromara/payment-spring-boot.git
synced 2026-03-14 05:43:46 +08:00
@@ -58,12 +58,7 @@ import java.security.cert.CertificateFactory;
|
|||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneOffset;
|
import java.time.ZoneOffset;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -96,7 +91,7 @@ public class SignatureProvider {
|
|||||||
/**
|
/**
|
||||||
* 微信平台证书容器 key = 序列号 value = 证书对象
|
* 微信平台证书容器 key = 序列号 value = 证书对象
|
||||||
*/
|
*/
|
||||||
private static final Map<String, X509WechatCertificateInfo> CERTIFICATE_MAP = new ConcurrentHashMap<>();
|
private static final Set<X509WechatCertificateInfo> CERTIFICATE_SET = Collections.synchronizedSet(new HashSet<>());
|
||||||
/**
|
/**
|
||||||
* 加密算法提供方 - BouncyCastle
|
* 加密算法提供方 - BouncyCastle
|
||||||
*/
|
*/
|
||||||
@@ -186,14 +181,21 @@ public class SignatureProvider {
|
|||||||
public boolean responseSignVerify(ResponseSignVerifyParams params) {
|
public boolean responseSignVerify(ResponseSignVerifyParams params) {
|
||||||
|
|
||||||
String wechatpaySerial = params.getWechatpaySerial();
|
String wechatpaySerial = params.getWechatpaySerial();
|
||||||
if (CERTIFICATE_MAP.isEmpty() || !CERTIFICATE_MAP.containsKey(wechatpaySerial)) {
|
X509WechatCertificateInfo certificate = CERTIFICATE_SET.stream()
|
||||||
wechatMetaContainer.getTenantIds().forEach(this::refreshCertificate);
|
.filter(cert -> Objects.equals(wechatpaySerial, cert.getWechatPaySerial()))
|
||||||
}
|
.findAny()
|
||||||
Certificate certificate = CERTIFICATE_MAP.get(wechatpaySerial).getX509Certificate();
|
.orElseGet(() -> {
|
||||||
|
wechatMetaContainer.getTenantIds().forEach(this::refreshCertificate);
|
||||||
|
return CERTIFICATE_SET.stream()
|
||||||
|
.filter(cert -> Objects.equals(wechatpaySerial, cert.getWechatPaySerial()))
|
||||||
|
.findAny()
|
||||||
|
.orElseThrow(()->new PayException("cannot obtain the certificate"));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
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);
|
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()));
|
||||||
@@ -235,7 +237,7 @@ public class SignatureProvider {
|
|||||||
}
|
}
|
||||||
ArrayNode certificates = bodyObjectNode.withArray("data");
|
ArrayNode certificates = bodyObjectNode.withArray("data");
|
||||||
if (certificates.isArray() && certificates.size() > 0) {
|
if (certificates.isArray() && certificates.size() > 0) {
|
||||||
CERTIFICATE_MAP.remove(tenantId);
|
CERTIFICATE_SET.remove(tenantId);
|
||||||
final CertificateFactory certificateFactory = CertificateFactory.getInstance("X509", BC_PROVIDER);
|
final CertificateFactory certificateFactory = CertificateFactory.getInstance("X509", BC_PROVIDER);
|
||||||
certificates.forEach(objectNode -> {
|
certificates.forEach(objectNode -> {
|
||||||
JsonNode encryptCertificate = objectNode.get("encrypt_certificate");
|
JsonNode encryptCertificate = objectNode.get("encrypt_certificate");
|
||||||
@@ -253,7 +255,7 @@ public class SignatureProvider {
|
|||||||
x509WechatCertificateInfo.setWechatPaySerial(responseSerialNo);
|
x509WechatCertificateInfo.setWechatPaySerial(responseSerialNo);
|
||||||
x509WechatCertificateInfo.setTenantId(tenantId);
|
x509WechatCertificateInfo.setTenantId(tenantId);
|
||||||
x509WechatCertificateInfo.setX509Certificate((X509Certificate) certificate);
|
x509WechatCertificateInfo.setX509Certificate((X509Certificate) certificate);
|
||||||
CERTIFICATE_MAP.put(responseSerialNo, x509WechatCertificateInfo);
|
CERTIFICATE_SET.add( x509WechatCertificateInfo);
|
||||||
} catch (CertificateException e) {
|
} catch (CertificateException e) {
|
||||||
throw new PayException("An error occurred while generating the wechat v3 certificate, reason : " + e.getMessage());
|
throw new PayException("An error occurred while generating the wechat v3 certificate, reason : " + e.getMessage());
|
||||||
}
|
}
|
||||||
@@ -296,7 +298,8 @@ public class SignatureProvider {
|
|||||||
throw new PayException(e);
|
throw new PayException(e);
|
||||||
}
|
}
|
||||||
return new String(bytes, StandardCharsets.UTF_8);
|
return new String(bytes, StandardCharsets.UTF_8);
|
||||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchProviderException e) {
|
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException |
|
||||||
|
InvalidAlgorithmParameterException | NoSuchProviderException e) {
|
||||||
throw new PayException(e);
|
throw new PayException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -336,10 +339,10 @@ public class SignatureProvider {
|
|||||||
WechatMetaBean wechatMetaBean = wechatMetaContainer.getWechatMeta(tenantId);
|
WechatMetaBean wechatMetaBean = wechatMetaContainer.getWechatMeta(tenantId);
|
||||||
PrivateKey privateKey = wechatMetaBean.getKeyPair().getPrivate();
|
PrivateKey privateKey = wechatMetaBean.getKeyPair().getPrivate();
|
||||||
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding", BC_PROVIDER);
|
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding", BC_PROVIDER);
|
||||||
cipher.init(Cipher.DECRYPT_MODE,privateKey);
|
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||||
byte[] data = Base64Utils.decodeFromString(message);
|
byte[] data = Base64Utils.decodeFromString(message);
|
||||||
byte[] cipherData = cipher.doFinal(data);
|
byte[] cipherData = cipher.doFinal(data);
|
||||||
return new String(cipherData,StandardCharsets.UTF_8);
|
return new String(cipherData, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new PayException(e);
|
throw new PayException(e);
|
||||||
@@ -353,22 +356,17 @@ public class SignatureProvider {
|
|||||||
* @return the x 509 wechat certificate info
|
* @return the x 509 wechat certificate info
|
||||||
*/
|
*/
|
||||||
public X509WechatCertificateInfo getCertificate(String tenantId) {
|
public X509WechatCertificateInfo getCertificate(String tenantId) {
|
||||||
for (String serial : CERTIFICATE_MAP.keySet()) {
|
|
||||||
X509WechatCertificateInfo wechatCertificateInfo = CERTIFICATE_MAP.get(serial);
|
|
||||||
X509Certificate x509Cert = wechatCertificateInfo.getX509Certificate();
|
|
||||||
if (wechatCertificateInfo.getTenantId().equals(tenantId)){
|
|
||||||
try {
|
|
||||||
x509Cert.checkValidity();
|
|
||||||
|
|
||||||
return wechatCertificateInfo;
|
return CERTIFICATE_SET.stream()
|
||||||
} catch (Exception e) {
|
.filter(cert -> Objects.equals(tenantId, cert.getTenantId()))
|
||||||
log.warn("the wechat certificate is invalid , {}", e.getMessage());
|
.findAny()
|
||||||
// Async?
|
.orElseGet(() -> {
|
||||||
wechatMetaContainer.getTenantIds().forEach(this::refreshCertificate);
|
wechatMetaContainer.getTenantIds().forEach(this::refreshCertificate);
|
||||||
}
|
return CERTIFICATE_SET.stream()
|
||||||
}
|
.filter(cert -> Objects.equals(tenantId, cert.getTenantId()))
|
||||||
}
|
.findAny()
|
||||||
throw new PayException("failed to obtain wechat pay x509Certificate ");
|
.orElseThrow(() -> new PayException("cannot obtain the certificate"));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user