更新完成:完成微信支付的功能开发和测试
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
package com.gxwebsoft.common.core.utils;
|
||||
|
||||
import com.gxwebsoft.common.core.config.CertificateProperties;
|
||||
import com.gxwebsoft.common.system.entity.Payment;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* 微信支付配置验证工具
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2025-07-27
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class WechatPayConfigValidator {
|
||||
|
||||
private final CertificateProperties certConfig;
|
||||
private final CertificateLoader certificateLoader;
|
||||
|
||||
public WechatPayConfigValidator(CertificateProperties certConfig, CertificateLoader certificateLoader) {
|
||||
this.certConfig = certConfig;
|
||||
this.certificateLoader = certificateLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证微信支付配置
|
||||
*
|
||||
* @param payment 支付配置
|
||||
* @param tenantId 租户ID
|
||||
* @return 验证结果
|
||||
*/
|
||||
public ValidationResult validateWechatPayConfig(Payment payment, Integer tenantId) {
|
||||
ValidationResult result = new ValidationResult();
|
||||
|
||||
log.info("开始验证微信支付配置 - 租户ID: {}", tenantId);
|
||||
|
||||
// 1. 验证基本配置
|
||||
if (payment == null) {
|
||||
result.addError("支付配置为空");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(payment.getMchId())) {
|
||||
result.addError("商户号未配置");
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(payment.getAppId())) {
|
||||
result.addError("应用ID未配置");
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(payment.getMerchantSerialNumber())) {
|
||||
result.addError("商户证书序列号未配置");
|
||||
}
|
||||
|
||||
// 2. 验证 APIv3 密钥
|
||||
String apiV3Key = getValidApiV3Key(payment);
|
||||
if (!StringUtils.hasText(apiV3Key)) {
|
||||
result.addError("APIv3密钥未配置");
|
||||
} else {
|
||||
validateApiV3Key(apiV3Key, result);
|
||||
}
|
||||
|
||||
// 3. 验证证书文件
|
||||
validateCertificateFiles(tenantId, result);
|
||||
|
||||
// 4. 记录验证结果
|
||||
if (result.isValid()) {
|
||||
log.info("✅ 微信支付配置验证通过 - 租户ID: {}", tenantId);
|
||||
} else {
|
||||
log.error("❌ 微信支付配置验证失败 - 租户ID: {}, 错误: {}", tenantId, result.getErrors());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取有效的 APIv3 密钥
|
||||
* 优先使用数据库配置,如果为空则使用配置文件默认值
|
||||
*/
|
||||
public String getValidApiV3Key(Payment payment) {
|
||||
String apiV3Key = payment.getApiKey();
|
||||
|
||||
if (!StringUtils.hasText(apiV3Key)) {
|
||||
apiV3Key = certConfig.getWechatPay().getDev().getApiV3Key();
|
||||
log.warn("数据库中APIv3密钥为空,使用配置文件默认值");
|
||||
}
|
||||
|
||||
return apiV3Key;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证 APIv3 密钥格式
|
||||
*/
|
||||
private void validateApiV3Key(String apiV3Key, ValidationResult result) {
|
||||
if (apiV3Key.length() != 32) {
|
||||
result.addError("APIv3密钥长度错误,应为32位,实际为: " + apiV3Key.length());
|
||||
}
|
||||
|
||||
if (!apiV3Key.matches("^[a-zA-Z0-9]+$")) {
|
||||
result.addError("APIv3密钥格式错误,应仅包含字母和数字");
|
||||
}
|
||||
|
||||
log.info("APIv3密钥验证 - 长度: {}, 格式: {}",
|
||||
apiV3Key.length(),
|
||||
apiV3Key.matches("^[a-zA-Z0-9]+$") ? "正确" : "错误");
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证证书文件
|
||||
*/
|
||||
private void validateCertificateFiles(Integer tenantId, ValidationResult result) {
|
||||
String tenantCertPath = "dev/wechat/" + tenantId;
|
||||
String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile();
|
||||
|
||||
if (!certificateLoader.certificateExists(privateKeyPath)) {
|
||||
result.addError("证书文件不存在: " + privateKeyPath);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
String privateKey = certificateLoader.loadCertificatePath(privateKeyPath);
|
||||
log.info("✅ 证书文件验证通过: {}", privateKey);
|
||||
} catch (Exception e) {
|
||||
result.addError("证书文件加载失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证结果类
|
||||
*/
|
||||
public static class ValidationResult {
|
||||
private boolean valid = true;
|
||||
private StringBuilder errors = new StringBuilder();
|
||||
|
||||
public void addError(String error) {
|
||||
this.valid = false;
|
||||
if (errors.length() > 0) {
|
||||
errors.append("; ");
|
||||
}
|
||||
errors.append(error);
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return valid;
|
||||
}
|
||||
|
||||
public String getErrors() {
|
||||
return errors.toString();
|
||||
}
|
||||
|
||||
public void logErrors() {
|
||||
if (!valid) {
|
||||
log.error("配置验证失败: {}", errors.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成配置诊断报告
|
||||
*/
|
||||
public String generateDiagnosticReport(Payment payment, Integer tenantId) {
|
||||
StringBuilder report = new StringBuilder();
|
||||
report.append("=== 微信支付配置诊断报告 ===\n");
|
||||
report.append("租户ID: ").append(tenantId).append("\n");
|
||||
|
||||
if (payment != null) {
|
||||
report.append("商户号: ").append(payment.getMchId()).append("\n");
|
||||
report.append("应用ID: ").append(payment.getAppId()).append("\n");
|
||||
report.append("商户证书序列号: ").append(payment.getMerchantSerialNumber()).append("\n");
|
||||
|
||||
String dbApiKey = payment.getApiKey();
|
||||
String configApiKey = certConfig.getWechatPay().getDev().getApiV3Key();
|
||||
|
||||
report.append("数据库APIv3密钥: ").append(dbApiKey != null ? "已配置(" + dbApiKey.length() + "位)" : "未配置").append("\n");
|
||||
report.append("配置文件APIv3密钥: ").append(configApiKey != null ? "已配置(" + configApiKey.length() + "位)" : "未配置").append("\n");
|
||||
|
||||
String finalApiKey = getValidApiV3Key(payment);
|
||||
report.append("最终使用APIv3密钥: ").append(finalApiKey != null ? "已配置(" + finalApiKey.length() + "位)" : "未配置").append("\n");
|
||||
|
||||
} else {
|
||||
report.append("❌ 支付配置为空\n");
|
||||
}
|
||||
|
||||
// 证书文件检查
|
||||
String tenantCertPath = "dev/wechat/" + tenantId;
|
||||
String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile();
|
||||
boolean certExists = certificateLoader.certificateExists(privateKeyPath);
|
||||
|
||||
report.append("证书文件路径: ").append(privateKeyPath).append("\n");
|
||||
report.append("证书文件存在: ").append(certExists ? "是" : "否").append("\n");
|
||||
|
||||
ValidationResult validation = validateWechatPayConfig(payment, tenantId);
|
||||
report.append("配置验证结果: ").append(validation.isValid() ? "通过" : "失败").append("\n");
|
||||
if (!validation.isValid()) {
|
||||
report.append("验证错误: ").append(validation.getErrors()).append("\n");
|
||||
}
|
||||
|
||||
report.append("=== 诊断报告结束 ===");
|
||||
|
||||
return report.toString();
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import com.gxwebsoft.common.core.config.CertificateProperties;
|
||||
import com.gxwebsoft.common.core.utils.RedisUtil;
|
||||
import com.gxwebsoft.common.core.utils.CertificateLoader;
|
||||
import com.gxwebsoft.common.core.utils.WechatCertAutoConfig;
|
||||
import com.gxwebsoft.common.core.utils.WechatPayConfigValidator;
|
||||
import com.gxwebsoft.common.core.web.BaseController;
|
||||
import com.gxwebsoft.common.system.entity.Payment;
|
||||
import com.gxwebsoft.shop.service.ShopOrderGoodsService;
|
||||
@@ -70,6 +71,8 @@ public class ShopOrderController extends BaseController {
|
||||
private CertificateLoader certificateLoader;
|
||||
@Resource
|
||||
private WechatCertAutoConfig wechatCertAutoConfig;
|
||||
@Resource
|
||||
private WechatPayConfigValidator wechatPayConfigValidator;
|
||||
@Value("${spring.profiles.active}")
|
||||
String active;
|
||||
|
||||
@@ -221,6 +224,15 @@ public class ShopOrderController extends BaseController {
|
||||
logger.info("开始处理微信支付异步通知 - 租户ID: {}", tenantId);
|
||||
logger.info("支付配置信息 - 商户号: {}, 应用ID: {}", payment.getMchId(), payment.getAppId());
|
||||
|
||||
// 验证微信支付配置
|
||||
WechatPayConfigValidator.ValidationResult validation = wechatPayConfigValidator.validateWechatPayConfig(payment, tenantId);
|
||||
if (!validation.isValid()) {
|
||||
logger.error("❌ 微信支付配置验证失败: {}", validation.getErrors());
|
||||
logger.info("📋 配置诊断报告:\n{}", wechatPayConfigValidator.generateDiagnosticReport(payment, tenantId));
|
||||
throw new RuntimeException("微信支付配置验证失败: " + validation.getErrors());
|
||||
}
|
||||
logger.info("✅ 微信支付配置验证通过");
|
||||
|
||||
RequestParam requestParam = new RequestParam.Builder()
|
||||
.serialNumber(header.get("wechatpay-serial"))
|
||||
.nonce(header.get("wechatpay-nonce"))
|
||||
@@ -236,8 +248,25 @@ public class ShopOrderController extends BaseController {
|
||||
// 开发环境 - 构建包含租户号的私钥路径
|
||||
String tenantCertPath = "dev/wechat/" + tenantId;
|
||||
String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile();
|
||||
|
||||
logger.info("开发环境异步通知证书路径: {}", privateKeyPath);
|
||||
logger.info("租户ID: {}, 证书目录: {}", tenantId, tenantCertPath);
|
||||
|
||||
// 检查证书文件是否存在
|
||||
if (!certificateLoader.certificateExists(privateKeyPath)) {
|
||||
logger.error("证书文件不存在: {}", privateKeyPath);
|
||||
throw new RuntimeException("证书文件不存在: " + privateKeyPath);
|
||||
}
|
||||
|
||||
String privateKey = certificateLoader.loadCertificatePath(privateKeyPath);
|
||||
String apiV3Key = certConfig.getWechatPay().getDev().getApiV3Key();
|
||||
|
||||
// 使用验证器获取有效的 APIv3 密钥
|
||||
String apiV3Key = wechatPayConfigValidator.getValidApiV3Key(payment);
|
||||
|
||||
logger.info("私钥文件加载成功: {}", privateKey);
|
||||
logger.info("使用APIv3密钥来源: {}", payment.getApiKey() != null && !payment.getApiKey().trim().isEmpty() ? "数据库配置" : "配置文件默认");
|
||||
logger.info("APIv3密钥长度: {}", apiV3Key != null ? apiV3Key.length() : 0);
|
||||
logger.info("商户证书序列号: {}", payment.getMerchantSerialNumber());
|
||||
|
||||
// 使用自动证书配置
|
||||
config = new RSAAutoCertificateConfig.Builder()
|
||||
@@ -247,7 +276,7 @@ public class ShopOrderController extends BaseController {
|
||||
.apiV3Key(apiV3Key)
|
||||
.build();
|
||||
|
||||
logger.info("开发环境使用自动证书配置创建通知解析器");
|
||||
logger.info("✅ 开发环境使用自动证书配置创建通知解析器成功");
|
||||
} else {
|
||||
// 生产环境 - 使用自动证书配置
|
||||
final String certRootPath = certConfig.getCertRootPath();
|
||||
@@ -268,19 +297,30 @@ public class ShopOrderController extends BaseController {
|
||||
.apiV3Key(apiV3Key)
|
||||
.build();
|
||||
|
||||
logger.info("生产环境使用自动证书配置创建通知解析器");
|
||||
logger.info("✅ 生产环境使用自动证书配置创建通知解析器成功");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("创建通知配置失败", e);
|
||||
logger.error("❌ 创建通知配置失败 - 租户ID: {}, 商户号: {}", tenantId, payment.getMchId(), e);
|
||||
logger.error("🔍 错误详情: {}", e.getMessage());
|
||||
logger.error("💡 请检查:");
|
||||
logger.error("1. 证书文件是否存在且路径正确");
|
||||
logger.error("2. APIv3密钥是否配置正确");
|
||||
logger.error("3. 商户证书序列号是否正确");
|
||||
logger.error("4. 网络连接是否正常");
|
||||
throw new RuntimeException("微信支付通知配置失败: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
// 初始化 NotificationParser
|
||||
NotificationParser parser = new NotificationParser(config);
|
||||
logger.info("✅ 通知解析器创建成功,准备解析异步通知");
|
||||
|
||||
// 以支付通知回调为例,验签、解密并转换成 Transaction
|
||||
try {
|
||||
logger.info("开始解析微信支付异步通知...");
|
||||
Transaction transaction = parser.parse(requestParam, Transaction.class);
|
||||
logger.info("✅ 异步通知解析成功 - 交易状态: {}, 商户订单号: {}",
|
||||
transaction.getTradeStateDesc(), transaction.getOutTradeNo());
|
||||
|
||||
if (StrUtil.equals("支付成功", transaction.getTradeStateDesc())) {
|
||||
final String outTradeNo = transaction.getOutTradeNo();
|
||||
final String transactionId = transaction.getTransactionId();
|
||||
@@ -315,10 +355,20 @@ public class ShopOrderController extends BaseController {
|
||||
return "SUCCESS";
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
System.out.println($e.getMessage());
|
||||
} catch (Exception e) {
|
||||
logger.error("❌ 处理微信支付异步通知失败 - 租户ID: {}, 商户号: {}", tenantId, payment.getMchId(), e);
|
||||
logger.error("🔍 异常详情: {}", e.getMessage());
|
||||
logger.error("💡 可能的原因:");
|
||||
logger.error("1. 证书配置错误或证书文件损坏");
|
||||
logger.error("2. 微信支付平台证书已过期");
|
||||
logger.error("3. 签名验证失败");
|
||||
logger.error("4. 请求参数格式错误");
|
||||
|
||||
// 返回失败,微信会重试
|
||||
return "fail";
|
||||
}
|
||||
|
||||
logger.warn("⚠️ 异步通知处理完成但未找到匹配的支付成功状态");
|
||||
return "fail";
|
||||
}
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ certificate:
|
||||
# 微信支付证书配置
|
||||
wechat-pay:
|
||||
dev:
|
||||
api-v3-key: "zGufUcqa7ovgxRL0kF5OlPr482EZwtn9"
|
||||
api-v3-key: "0kF5OlPr482EZwtn9zGufUcqa7ovgxRL"
|
||||
private-key-file: "apiclient_key.pem"
|
||||
apiclient-cert-file: "apiclient_cert.pem"
|
||||
wechatpay-cert-file: "wechatpay_cert.pem"
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDqDCCApCgAwIBAgIQICISFUe9Mqj+pWqb2fs9jDANBgkqhkiG9w0BAQsFADCBkTELMAkGA1UE
|
||||
BhMCQ04xGzAZBgNVBAoMEkFudCBGaW5hbmNpYWwgdGVzdDElMCMGA1UECwwcQ2VydGlmaWNhdGlv
|
||||
biBBdXRob3JpdHkgdGVzdDE+MDwGA1UEAww1QW50IEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1
|
||||
dGhvcml0eSBDbGFzcyAyIFIxIHRlc3QwHhcNMjIxMjE1MDExMjA0WhcNMjMxMjE1MDExMjA0WjB6
|
||||
MQswCQYDVQQGEwJDTjEVMBMGA1UECgwM5rKZ566x546v5aKDMQ8wDQYDVQQLDAZBbGlwYXkxQzBB
|
||||
BgNVBAMMOuaUr+S7mOWunSjkuK3lm70p572R57uc5oqA5pyv5pyJ6ZmQ5YWs5Y+4LTIwODgxMDIx
|
||||
NzUyMDcyOTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCQwLlj0xdcIy4rQLNg73Nl
|
||||
zjSqKV7cjE1aieYpEQ/0aNZxVBqm0wxSiXgDR+NjyuD2VadER6caFDhB9bO2lLroI9xHjc1Griwc
|
||||
4XAN9JA2kh/3irzQxKCBzrW0/6gpEIIVFSK+reCAmD0vtMTLOIChUhl4OSDYWLpUzFmICa9tRNGD
|
||||
hPUSr08JFn2DhXW3eUnOzJEkf4qxn3HIDlKwBb50CJhjkuCIWxKBxRe1oQy2zEd6tezp00xvW4DQ
|
||||
OqkSHEW641sUbA7ntckdOF7X5FQGKqKqwrFxTSblixk/mkBxAkIj7dM+k9AqFtrhnzn01sP21MYx
|
||||
PPOhddGk3indwe9DAgMBAAGjEjAQMA4GA1UdDwEB/wQEAwIE8DANBgkqhkiG9w0BAQsFAAOCAQEA
|
||||
xJXsNQ5rDQBwn8BXYuSaj1Hkw8W3wKRr55Y2fDoQIx2kek9kI53PRvIVAdxlrLxZ6z+lTFrkThJ/
|
||||
rsH84ffkDvfSTca3QCB6c01jveQ+qGvGQSx/HPu92DMT/hJ0V8LstLlq6Q1r8hTvcjHOPyE9l3vF
|
||||
I0Ozbe2F3TCOFFjtEjHHOw9bo+tB8gtiY/bfidPbTtCClTTyPRTE8MuzQqDABhGl3khL4aue9h8g
|
||||
x0i0yAn15VBf9ruqlTrTnhuI5ak7AOwdxjKaMwVbTCy838rQjt4xKMD80h2go/6MLRGidnbeiTU2
|
||||
Uq3PVgEJo2kxE8ZSD7x4JtskZD07YCSA5DZtuw==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDszCCApugAwIBAgIQIBkIGbgVxq210KxLJ+YA/TANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UE
|
||||
BhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxJTAjBgNVBAsMHENlcnRpZmljYXRpb24gQXV0
|
||||
aG9yaXR5IHRlc3QxNjA0BgNVBAMMLUFudCBGaW5hbmNpYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
|
||||
dHkgUjEgdGVzdDAeFw0xOTA4MTkxMTE2MDBaFw0yNDA4MDExMTE2MDBaMIGRMQswCQYDVQQGEwJD
|
||||
TjEbMBkGA1UECgwSQW50IEZpbmFuY2lhbCB0ZXN0MSUwIwYDVQQLDBxDZXJ0aWZpY2F0aW9uIEF1
|
||||
dGhvcml0eSB0ZXN0MT4wPAYDVQQDDDVBbnQgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y
|
||||
aXR5IENsYXNzIDIgUjEgdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMh4FKYO
|
||||
ZyRQHD6eFbPKZeSAnrfjfU7xmS9Yoozuu+iuqZlb6Z0SPLUqqTZAFZejOcmr07ln/pwZxluqplxC
|
||||
5+B48End4nclDMlT5HPrDr3W0frs6Xsa2ZNcyil/iKNB5MbGll8LRAxntsKvZZj6vUTMb705gYgm
|
||||
VUMILwi/ZxKTQqBtkT/kQQ5y6nOZsj7XI5rYdz6qqOROrpvS/d7iypdHOMIM9Iz9DlL1mrCykbBi
|
||||
t25y+gTeXmuisHUwqaRpwtCGK4BayCqxRGbNipe6W73EK9lBrrzNtTr9NaysesT/v+l25JHCL9tG
|
||||
wpNr1oWFzk4IHVOg0ORiQ6SUgxZUTYcCAwEAAaMSMBAwDgYDVR0PAQH/BAQDAgTwMA0GCSqGSIb3
|
||||
DQEBCwUAA4IBAQBWThEoIaQoBX2YeRY/I8gu6TYnFXtyuCljANnXnM38ft+ikhE5mMNgKmJYLHvT
|
||||
yWWWgwHoSAWEuml7EGbE/2AK2h3k0MdfiWLzdmpPCRG/RJHk6UB1pMHPilI+c0MVu16OPpKbg5Vf
|
||||
LTv7dsAB40AzKsvyYw88/Ezi1osTXo6QQwda7uefvudirtb8FcQM9R66cJxl3kt1FXbpYwheIm/p
|
||||
j1mq64swCoIYu4NrsUYtn6CV542DTQMI5QdXkn+PzUUly8F6kDp+KpMNd0avfWNL5+O++z+F5Szy
|
||||
1CPta1D7EQ/eYmMP+mOQ35oifWIoFCpN6qQVBS/Hob1J/UUyg7BW
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,88 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBszCCAVegAwIBAgIIaeL+wBcKxnswDAYIKoEcz1UBg3UFADAuMQswCQYDVQQG
|
||||
EwJDTjEOMAwGA1UECgwFTlJDQUMxDzANBgNVBAMMBlJPT1RDQTAeFw0xMjA3MTQw
|
||||
MzExNTlaFw00MjA3MDcwMzExNTlaMC4xCzAJBgNVBAYTAkNOMQ4wDAYDVQQKDAVO
|
||||
UkNBQzEPMA0GA1UEAwwGUk9PVENBMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE
|
||||
MPCca6pmgcchsTf2UnBeL9rtp4nw+itk1Kzrmbnqo05lUwkwlWK+4OIrtFdAqnRT
|
||||
V7Q9v1htkv42TsIutzd126NdMFswHwYDVR0jBBgwFoAUTDKxl9kzG8SmBcHG5Yti
|
||||
W/CXdlgwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFEwysZfZ
|
||||
MxvEpgXBxuWLYlvwl3ZYMAwGCCqBHM9VAYN1BQADSAAwRQIgG1bSLeOXp3oB8H7b
|
||||
53W+CKOPl2PknmWEq/lMhtn25HkCIQDaHDgWxWFtnCrBjH16/W3Ezn7/U/Vjo5xI
|
||||
pDoiVhsLwg==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF0zCCA7ugAwIBAgIIH8+hjWpIDREwDQYJKoZIhvcNAQELBQAwejELMAkGA1UE
|
||||
BhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNVBAsMF0NlcnRpZmlj
|
||||
YXRpb24gQXV0aG9yaXR5MTEwLwYDVQQDDChBbnQgRmluYW5jaWFsIENlcnRpZmlj
|
||||
YXRpb24gQXV0aG9yaXR5IFIxMB4XDTE4MDMyMTEzNDg0MFoXDTM4MDIyODEzNDg0
|
||||
MFowejELMAkGA1UEBhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNV
|
||||
BAsMF0NlcnRpZmljYXRpb24gQXV0aG9yaXR5MTEwLwYDVQQDDChBbnQgRmluYW5j
|
||||
aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFIxMIICIjANBgkqhkiG9w0BAQEF
|
||||
AAOCAg8AMIICCgKCAgEAtytTRcBNuur5h8xuxnlKJetT65cHGemGi8oD+beHFPTk
|
||||
rUTlFt9Xn7fAVGo6QSsPb9uGLpUFGEdGmbsQ2q9cV4P89qkH04VzIPwT7AywJdt2
|
||||
xAvMs+MgHFJzOYfL1QkdOOVO7NwKxH8IvlQgFabWomWk2Ei9WfUyxFjVO1LVh0Bp
|
||||
dRBeWLMkdudx0tl3+21t1apnReFNQ5nfX29xeSxIhesaMHDZFViO/DXDNW2BcTs6
|
||||
vSWKyJ4YIIIzStumD8K1xMsoaZBMDxg4itjWFaKRgNuPiIn4kjDY3kC66Sl/6yTl
|
||||
YUz8AybbEsICZzssdZh7jcNb1VRfk79lgAprm/Ktl+mgrU1gaMGP1OE25JCbqli1
|
||||
Pbw/BpPynyP9+XulE+2mxFwTYhKAwpDIDKuYsFUXuo8t261pCovI1CXFzAQM2w7H
|
||||
DtA2nOXSW6q0jGDJ5+WauH+K8ZSvA6x4sFo4u0KNCx0ROTBpLif6GTngqo3sj+98
|
||||
SZiMNLFMQoQkjkdN5Q5g9N6CFZPVZ6QpO0JcIc7S1le/g9z5iBKnifrKxy0TQjtG
|
||||
PsDwc8ubPnRm/F82RReCoyNyx63indpgFfhN7+KxUIQ9cOwwTvemmor0A+ZQamRe
|
||||
9LMuiEfEaWUDK+6O0Gl8lO571uI5onYdN1VIgOmwFbe+D8TcuzVjIZ/zvHrAGUcC
|
||||
AwEAAaNdMFswCwYDVR0PBAQDAgEGMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFF90
|
||||
tATATwda6uWx2yKjh0GynOEBMB8GA1UdIwQYMBaAFF90tATATwda6uWx2yKjh0Gy
|
||||
nOEBMA0GCSqGSIb3DQEBCwUAA4ICAQCVYaOtqOLIpsrEikE5lb+UARNSFJg6tpkf
|
||||
tJ2U8QF/DejemEHx5IClQu6ajxjtu0Aie4/3UnIXop8nH/Q57l+Wyt9T7N2WPiNq
|
||||
JSlYKYbJpPF8LXbuKYG3BTFTdOVFIeRe2NUyYh/xs6bXGr4WKTXb3qBmzR02FSy3
|
||||
IODQw5Q6zpXj8prYqFHYsOvGCEc1CwJaSaYwRhTkFedJUxiyhyB5GQwoFfExCVHW
|
||||
05ZFCAVYFldCJvUzfzrWubN6wX0DD2dwultgmldOn/W/n8at52mpPNvIdbZb2F41
|
||||
T0YZeoWnCJrYXjq/32oc1cmifIHqySnyMnavi75DxPCdZsCOpSAT4j4lAQRGsfgI
|
||||
kkLPGQieMfNNkMCKh7qjwdXAVtdqhf0RVtFILH3OyEodlk1HYXqX5iE5wlaKzDop
|
||||
PKwf2Q3BErq1xChYGGVS+dEvyXc/2nIBlt7uLWKp4XFjqekKbaGaLJdjYP5b2s7N
|
||||
1dM0MXQ/f8XoXKBkJNzEiM3hfsU6DOREgMc1DIsFKxfuMwX3EkVQM1If8ghb6x5Y
|
||||
jXayv+NLbidOSzk4vl5QwngO/JYFMkoc6i9LNwEaEtR9PhnrdubxmrtM+RjfBm02
|
||||
77q3dSWFESFQ4QxYWew4pHE0DpWbWy/iMIKQ6UZ5RLvB8GEcgt8ON7BBJeMc+Dyi
|
||||
kT9qhqn+lw==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICiDCCAgygAwIBAgIIQX76UsB/30owDAYIKoZIzj0EAwMFADB6MQswCQYDVQQG
|
||||
EwJDTjEWMBQGA1UECgwNQW50IEZpbmFuY2lhbDEgMB4GA1UECwwXQ2VydGlmaWNh
|
||||
dGlvbiBBdXRob3JpdHkxMTAvBgNVBAMMKEFudCBGaW5hbmNpYWwgQ2VydGlmaWNh
|
||||
dGlvbiBBdXRob3JpdHkgRTEwHhcNMTkwNDI4MTYyMDQ0WhcNNDkwNDIwMTYyMDQ0
|
||||
WjB6MQswCQYDVQQGEwJDTjEWMBQGA1UECgwNQW50IEZpbmFuY2lhbDEgMB4GA1UE
|
||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxMTAvBgNVBAMMKEFudCBGaW5hbmNp
|
||||
YWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRTEwdjAQBgcqhkjOPQIBBgUrgQQA
|
||||
IgNiAASCCRa94QI0vR5Up9Yr9HEupz6hSoyjySYqo7v837KnmjveUIUNiuC9pWAU
|
||||
WP3jwLX3HkzeiNdeg22a0IZPoSUCpasufiLAnfXh6NInLiWBrjLJXDSGaY7vaokt
|
||||
rpZvAdmjXTBbMAsGA1UdDwQEAwIBBjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBRZ
|
||||
4ZTgDpksHL2qcpkFkxD2zVd16TAfBgNVHSMEGDAWgBRZ4ZTgDpksHL2qcpkFkxD2
|
||||
zVd16TAMBggqhkjOPQQDAwUAA2gAMGUCMQD4IoqT2hTUn0jt7oXLdMJ8q4vLp6sg
|
||||
wHfPiOr9gxreb+e6Oidwd2LDnC4OUqCWiF8CMAzwKs4SnDJYcMLf2vpkbuVE4dTH
|
||||
Rglz+HGcTLWsFs4KxLsq7MuU+vJTBUeDJeDjdA==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDxTCCAq2gAwIBAgIUEMdk6dVgOEIS2cCP0Q43P90Ps5YwDQYJKoZIhvcNAQEF
|
||||
BQAwajELMAkGA1UEBhMCQ04xEzARBgNVBAoMCmlUcnVzQ2hpbmExHDAaBgNVBAsM
|
||||
E0NoaW5hIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMMH2lUcnVzQ2hpbmEgQ2xhc3Mg
|
||||
MiBSb290IENBIC0gRzMwHhcNMTMwNDE4MDkzNjU2WhcNMzMwNDE4MDkzNjU2WjBq
|
||||
MQswCQYDVQQGEwJDTjETMBEGA1UECgwKaVRydXNDaGluYTEcMBoGA1UECwwTQ2hp
|
||||
bmEgVHJ1c3QgTmV0d29yazEoMCYGA1UEAwwfaVRydXNDaGluYSBDbGFzcyAyIFJv
|
||||
b3QgQ0EgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOPPShpV
|
||||
nJbMqqCw6Bz1kehnoPst9pkr0V9idOwU2oyS47/HjJXk9Rd5a9xfwkPO88trUpz5
|
||||
4GmmwspDXjVFu9L0eFaRuH3KMha1Ak01citbF7cQLJlS7XI+tpkTGHEY5pt3EsQg
|
||||
wykfZl/A1jrnSkspMS997r2Gim54cwz+mTMgDRhZsKK/lbOeBPpWtcFizjXYCqhw
|
||||
WktvQfZBYi6o4sHCshnOswi4yV1p+LuFcQ2ciYdWvULh1eZhLxHbGXyznYHi0dGN
|
||||
z+I9H8aXxqAQfHVhbdHNzi77hCxFjOy+hHrGsyzjrd2swVQ2iUWP8BfEQqGLqM1g
|
||||
KgWKYfcTGdbPB1MCAwEAAaNjMGEwHQYDVR0OBBYEFG/oAMxTVe7y0+408CTAK8hA
|
||||
uTyRMB8GA1UdIwQYMBaAFG/oAMxTVe7y0+408CTAK8hAuTyRMA8GA1UdEwEB/wQF
|
||||
MAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBLnUTfW7hp
|
||||
emMbuUGCk7RBswzOT83bDM6824EkUnf+X0iKS95SUNGeeSWK2o/3ALJo5hi7GZr3
|
||||
U8eLaWAcYizfO99UXMRBPw5PRR+gXGEronGUugLpxsjuynoLQu8GQAeysSXKbN1I
|
||||
UugDo9u8igJORYA+5ms0s5sCUySqbQ2R5z/GoceyI9LdxIVa1RjVX8pYOj8JFwtn
|
||||
DJN3ftSFvNMYwRuILKuqUYSHc2GPYiHVflDh5nDymCMOQFcFG3WsEuB+EYQPFgIU
|
||||
1DHmdZcz7Llx8UOZXX2JupWCYzK1XhJb+r4hK5ncf/w8qGtYlmyJpxk3hr1TfUJX
|
||||
Yf4Zr0fJsGuv
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,25 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEKzCCAxOgAwIBAgIUSHSWE7QKqPHXaFg/w1I1jhPrWvAwDQYJKoZIhvcNAQEL
|
||||
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
|
||||
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
|
||||
Q0EwHhcNMjQwNTExMDk0MzIzWhcNMjkwNTEwMDk0MzIzWjCBhDETMBEGA1UEAwwK
|
||||
MTI0NjYxMDEwMTEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTAwLgYDVQQL
|
||||
DCfljZflroHluILnvZHlrr/kv6Hmga/np5HmioDmnInpmZDlhazlj7gxCzAJBgNV
|
||||
BAYTAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
ADCCAQoCggEBAJSGQstwTNKfEUWGGNRdzAG691PKkpa78IV7SNAaAWdBUohvSGQB
|
||||
Hxg2JcTjnNifqxWAVj302u0+OEPETQ+teTLeLgRfGp4b8WBKdibn9RzZD964xGhM
|
||||
NkcMEwUxdqfBK28kGaKYW0zBifkzS1LDGuEVmUo9jE7pAuzDz5mJwcd1fZs4NsjD
|
||||
7O60QLw4SZCXINW6IYVc41Ln+RlY2XPkm/keBydjrfvMI7Z+DqW/TEWOWshNycYr
|
||||
3hqVeipz2FnUwK4ruGxEOqTXhYtn0QtvYaMcrfcXJ1U+zuwtZf+kh3RI/Lk+y2rJ
|
||||
kfnuxZZ+P5K2oG+hcBapYS3q15kmf9RpMH0CAwEAAaOBuTCBtjAJBgNVHRMEAjAA
|
||||
MAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDovL2V2
|
||||
Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUwREJD
|
||||
MDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJFMTJC
|
||||
MjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IBAQCK
|
||||
sgR2Wgb9wyyLX7ltlGXDqT44aMc3n5KI02LXv0mBD1aR4m5TFjlMzJIW2DIe01LF
|
||||
yxVsUsoGIpjnAkmQOdNPL3tnCfl3bWqdNDDH9B711llNe5y1i4IYOcObhX08dEQd
|
||||
vBnzuZ7/kH/t2h8q7rd7hqpQ5ZtU2xEY6ZlnohGyzNgVsDkLJI4b9iKRqOxRPVhs
|
||||
GGbGKrv3JAYiFouSeH/m04xMWARFKhPoWduIeSWEJZmszWfkUBvPXo26+0YOKBVN
|
||||
5gSkjioeXEX2T4/9K1SHx/iTzWvgN9MjlIJNujbg3Vz4PFU6aw2b8eK3Y0juto96
|
||||
2uoUN1fLIqxNOz2E4iSJ
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,28 +0,0 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCUhkLLcEzSnxFF
|
||||
hhjUXcwBuvdTypKWu/CFe0jQGgFnQVKIb0hkAR8YNiXE45zYn6sVgFY99NrtPjhD
|
||||
xE0PrXky3i4EXxqeG/FgSnYm5/Uc2Q/euMRoTDZHDBMFMXanwStvJBmimFtMwYn5
|
||||
M0tSwxrhFZlKPYxO6QLsw8+ZicHHdX2bODbIw+zutEC8OEmQlyDVuiGFXONS5/kZ
|
||||
WNlz5Jv5HgcnY637zCO2fg6lv0xFjlrITcnGK94alXoqc9hZ1MCuK7hsRDqk14WL
|
||||
Z9ELb2GjHK33FydVPs7sLWX/pId0SPy5PstqyZH57sWWfj+StqBvoXAWqWEt6teZ
|
||||
Jn/UaTB9AgMBAAECggEAb1Nvj5OeUaUfShBoXg3sU0O0DR9i3w8CCttMyYcklCO3
|
||||
XEKlbSgWCYzUpI7DSu/rSdOHUStOSdOAUvM5m824cbNtpKMwjWB+fWFyzFjDNhtR
|
||||
NO0jctXlPT3Ep/jaaoV1K/pQKLqwfIj5BUw4YlGRvTL2Ulpt59vp8FQZMIm8MOcw
|
||||
rNwYcUbMPaNKk4q3GF0LGvzW8k+S6wAWcAbx1KINRsLE0127o+shjGIlBiZgMJGZ
|
||||
nTMz4xdvVbojsMhdM8aEhq6GtmSHgBFKjETQPXiOjRDCGOM5yC/9R/9WsMGJmJ4m
|
||||
6Ec/RM4k9TZlnMZFsOZYO8S/kM+xgQUcAD8uGT1UgQKBgQDDGVZiqsDjudFcRkG/
|
||||
5pJN9PAC/Dk0Wzt6uRPZIhyFo2tDC/uL210Z5QR4hhB2nUSK8ANfAnepTotNzPHO
|
||||
DC/sO2NzLuZz5EZTLeg9ij9BZDK+0/6AiBT2XdBKR/uGZAffjFCDh+ujm44lbrRK
|
||||
7MUb9LtvDjPru1WVR0WhpFIwXQKBgQDC4xTQv6x3cPSW2SEglLVrl9CA68yO1g4T
|
||||
MphCav64Cl9UDk1ov5C2SCvshFbWlIBv2g7tqb/bUk8nj42GuZWBu1spkUt2y7HS
|
||||
eO89BmnaRNkVtWT8GtSMYYrYYAd23IGiOHPQqMnw/6HXkpjonpBa9c9CfEPwNtdq
|
||||
84pgqed+oQKBgC6rV/PAPuX6pC87iyzZffPx/JvqM9DnZgIEVdAiDcqV/emK60BY
|
||||
WBwCoaAnCbcmBahqo5PNpkw0wrP4q3sLhUcwKaj69huQ5pWtLJnUAS+mRVFKqt2a
|
||||
L9GDPXkXYP6T3SJHkVb1Y5O+eTFRGwW1P61hTJjTP+5K4L0V0H1LLnHtAoGAEDBU
|
||||
1lJVvUZAyxcWTWKM/3cI9uyffW4ClU2qoDnLFvalnJHjlEP1fW7ZVzhXDlQfpyrx
|
||||
+oQTT+CyepLOKtbXuIMbu4Q6RI//IYCyPtt9h4gYkFkVHmwMI+0mX3r6o8EFc7hE
|
||||
xpx+yeoyQ3oGAazKSQQKR3eTHS0xD81TPVxfwoECgYEAvBi3fPvIQ08pxk6kxj+S
|
||||
bypHo06JHT1Fi8pmKtKCGLduK85dCeBZqHmsorWC/qg4RgCFWFFKfrFTGTxC4nf8
|
||||
MRQHmKxq+SAh4SvFgRDA0lyaUWmw7H/JpolbBDIGnXhoDI0CmQU3s2xsQdJnNPIL
|
||||
azgaJXtOu+wr1MPR7Ij5OTU=
|
||||
-----END PRIVATE KEY-----
|
||||
@@ -1,19 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDjzCCAnegAwIBAgIQICISFPMNDPadFdV3VF7atzANBgkqhkiG9w0BAQsFADCBkTELMAkGA1UE
|
||||
BhMCQ04xGzAZBgNVBAoMEkFudCBGaW5hbmNpYWwgdGVzdDElMCMGA1UECwwcQ2VydGlmaWNhdGlv
|
||||
biBBdXRob3JpdHkgdGVzdDE+MDwGA1UEAww1QW50IEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1
|
||||
dGhvcml0eSBDbGFzcyAyIFIxIHRlc3QwHhcNMjIxMjE0MTEzNjE3WhcNMjMxMjE5MTEzNjE3WjBh
|
||||
MQswCQYDVQQGEwJDTjEVMBMGA1UECgwM5rKZ566x546v5aKDMQ8wDQYDVQQLDAZBbGlwYXkxKjAo
|
||||
BgNVBAMMITIwODgxMDIxNzUyMDcyOTItMjAxNjA5MTEwMDQ4OTQ4NjCCASIwDQYJKoZIhvcNAQEB
|
||||
BQADggEPADCCAQoCggEBAJFjmRNQkJ1d2kWZ4bn8WvIUWKu2+wMDQ5nOMaIGtKo+bx3o1RaAWYct
|
||||
XJL82GkdUr+JpiBy7W1iFl0quZJIo2n9tyxsTGTswq1mtYJVKonHELxN1L2Xz9PjU8wlzQwxb2Rm
|
||||
JlW2/SpUGaRiZxzYJHhHXbqvPH8D/xG+x6Hwq9zEF/ZIDMCLi5wiXhK7KFXDOBFYdOw0zwCmGIeY
|
||||
73htk56kay1HoTjwACvZzkw8ff5FRA76/5/7ZEj6R6Hga/LMmYJXfntPPYW/wuMiBI7rU5f4s6El
|
||||
S1A2uwK4+kbepg9klOYR2Lg30SNz4hj4k8KNtoeWnzrTlWoZj3SfDErJuuMCAwEAAaMSMBAwDgYD
|
||||
VR0PAQH/BAQDAgTwMA0GCSqGSIb3DQEBCwUAA4IBAQC9YAgw5uwHUgY73t8eABW8LzrhLoUafN/j
|
||||
WG6QataRgaTHbNCuCz5yWTMmD7hZGmb8NuZzaLOPD+/0yM5nz+w/nc+Emc6hzTCrBVtFX80nnM3j
|
||||
lIDBRGJRS2JlyrwL80DxoVCbY7JLkSRpGhc9RYLrNfPjpxhxchJ/8V1JU21rL5GKSdaR2YJDvANi
|
||||
Bth321Q0G6djxfLPjx3zXp8VTGDdhRZjblJ7EddK4kaQ3RKTm4+UivUYMMQ+esD8NnoHTGvDXRCi
|
||||
rqd+EtAZZ84yqW7YKKTjsh9a3tLBFwFMc2A2WM3s6fXtrFAiffsXwcyqaKTXibVTFE9t2sTUUaPF
|
||||
IoJu
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,23 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID3DCCAsSgAwIBAgIULdWgZpJjuuVeUr8/Nb9KQAai2qYwDQYJKoZIhvcNAQEL
|
||||
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
|
||||
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
|
||||
Q0EwHhcNMjAxMjA5MDMzMzIxWhcNMjUxMjA4MDMzMzIxWjBuMRgwFgYDVQQDDA9U
|
||||
ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl
|
||||
bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGDAJDTjERMA8GA1UEBwwIU2hlblpo
|
||||
ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDocR052ysMvkp3TkUb
|
||||
CDz5ntNm3wpPjy53ng6ZQKrMdt/HVKYzHplIO8zgYVKXgiCxlIVw8lAKAJ8uYrs/
|
||||
y2KOk2W1sMKb6t9ucKilaxYpCUuePj6ktMXPN/FIAgCIEXjrPuNHuPW6JA53yl6e
|
||||
wQoNPozbmYrcFFcRUnhHS9RWfSJm2OUBsAFh2O/o2APAhcIac0gPz/a6LWok3+vQ
|
||||
KnCqZcpGdnATwZ5H7oGmVVPHp8f5LwJYwp58ZHKxVHIHiLOeCXNNy7cnwv+vHBhy
|
||||
95GOdv9ZJRbcESGR7ASUkIKe5kDJhg5tjK3rKSjqUbe6qG6h5mSPvRy6oe6h9Ihf
|
||||
F8B1AgMBAAGjgYEwfzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DBlBgNVHR8EXjBc
|
||||
MFqgWKBWhlRodHRwOi8vZXZjYS5pdHJ1cy5jb20uY24vcHVibGljL2l0cnVzY3Js
|
||||
P0NBPTFCRDQyMjBFNTBEQkMwNEIwNkFEMzk3NTQ5ODQ2QzAxQzNFOEVCRDIwDQYJ
|
||||
KoZIhvcNAQELBQADggEBAGfRi4HT8Y6N1yJGmGpABiRJOqouDmktBxDhY12e2V5g
|
||||
mLfsr+aR4suOfaDbNigwjyQqYijOSlAJZobapNFazE9vUisVRa7FZUhzFLwxOo02
|
||||
mallcuDd7/rZuRtiovco+OAQVedAMwOgH6PCwK/QxUGNOpNpCQ5Y70z5ZAxb+IKR
|
||||
87WQvukZ/u2CqUpvEnwtj1PjuZ7sCqi9TpHhJtMMEZyzII7WB2jDFaIuaqrJDeSB
|
||||
qWASY04zfQ/FlLosaiXNxJCAT//0I6kM9iudwkuj+7bV8HESrdJcFe0yymIm3zOd
|
||||
Es6X0klx4QsyadXEHK5RSRIBdoGubHpm5fdVnYfSGok=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,24 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEFDCCAvygAwIBAgIUSjIxWE6Ttq53ggB00H6t6sy34iMwDQYJKoZIhvcNAQEL
|
||||
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
|
||||
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
|
||||
Q0EwHhcNMjMwOTE5MTUxNTQ4WhcNMjgwOTE3MTUxNTQ4WjBuMRgwFgYDVQQDDA9U
|
||||
ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl
|
||||
bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGDAJDTjERMA8GA1UEBwwIU2hlblpo
|
||||
ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5AOeoNuRReVPfOodE
|
||||
TTE/wq96OK/7MI1lkwgtRlOIqwFGbGPxPx+wiLweWOWAeGrd0h+YuktIZezLhMhB
|
||||
8pkJBzxz4U+zoQ9n3yY4CgDUBeAO8eNHhEQTTOTFUIvIlRxyr0EVuTHNP7pIkxA6
|
||||
gUvajWjJFbvU393vDHA9RflWrBNw1qVjkPPUx6axizD3wS8f77bwuspEWGTza/pS
|
||||
g96HWUwFh9OSlQNPOjPG4km2YRQwGhoRMlLeZsUB+a0PtV0HI/B0TbY5u2EmPt0R
|
||||
uNZLmcwImtiANYmySww6gp5uo4+im0P/kHKynPrW1SkS+8M9JP5T7Xck3bnHNv4S
|
||||
9UOPAgMBAAGjgbkwgbYwCQYDVR0TBAIwADALBgNVHQ8EBAMCA/gwgZsGA1UdHwSB
|
||||
kzCBkDCBjaCBiqCBh4aBhGh0dHA6Ly9ldmNhLml0cnVzLmNvbS5jbi9wdWJsaWMv
|
||||
aXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2QUQzOTc1NDk4NDZDMDFDM0U4
|
||||
RUJEMiZzZz1IQUNDNDcxQjY1NDIyRTEyQjI3QTlEMzNBODdBRDFDREY1OTI2RTE0
|
||||
MDM3MTANBgkqhkiG9w0BAQsFAAOCAQEAHd42YyvxvvjYEIkCURHweCSQpWQrdsnP
|
||||
AU2rcVzOx0kDxjq7+W2HkIkYeAZfE8pyBs5c39tgK+qospiDsKa9WYeBNyIRcCvN
|
||||
q9ObLqSV4Cy/8lQMNh4Q37cdc3X+pAlTr7MtKka8ZcXYvbMBqus0dfJZayZvW7Ak
|
||||
nnaXXJ4k7urgHOGYsZlZ+HC+DC/sYoN3DXzvg3XPlL0SNEQH0cWrRbaQnpOKVMk5
|
||||
TptbeNHKJfUxVW5jh4GtBFqvLeiOruY+gFYg7UkCKWo9ZIYe7/mEvJeHYh3acTTl
|
||||
DOl3L0fR5KR7vqFMwZEUZxVOs6K2ANSCr57OQPBV++MG4DPr3yOhCQ==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,91 +0,0 @@
|
||||
-- 检查支付配置的SQL脚本
|
||||
|
||||
-- 1. 查看所有支付配置
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
type,
|
||||
code,
|
||||
app_id,
|
||||
mch_id,
|
||||
CASE
|
||||
WHEN api_key IS NULL OR api_key = '' THEN '未配置'
|
||||
ELSE CONCAT('已配置(长度:', LENGTH(api_key), ')')
|
||||
END as api_key_status,
|
||||
merchant_serial_number,
|
||||
status,
|
||||
tenant_id,
|
||||
create_time
|
||||
FROM sys_payment
|
||||
ORDER BY type, tenant_id;
|
||||
|
||||
-- 2. 检查微信支付配置(type=0)
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
app_id,
|
||||
mch_id,
|
||||
CASE
|
||||
WHEN api_key IS NULL OR api_key = '' THEN 'ERROR: API密钥未配置'
|
||||
WHEN LENGTH(api_key) < 32 THEN 'WARNING: API密钥长度可能不正确'
|
||||
ELSE 'OK'
|
||||
END as api_key_check,
|
||||
CASE
|
||||
WHEN merchant_serial_number IS NULL OR merchant_serial_number = '' THEN 'ERROR: 序列号未配置'
|
||||
WHEN LENGTH(merchant_serial_number) != 40 THEN 'WARNING: 序列号长度可能不正确'
|
||||
ELSE 'OK'
|
||||
END as serial_number_check,
|
||||
CASE
|
||||
WHEN mch_id IS NULL OR mch_id = '' THEN 'ERROR: 商户号未配置'
|
||||
ELSE 'OK'
|
||||
END as mch_id_check,
|
||||
CASE
|
||||
WHEN app_id IS NULL OR app_id = '' THEN 'ERROR: 应用ID未配置'
|
||||
ELSE 'OK'
|
||||
END as app_id_check,
|
||||
status,
|
||||
tenant_id
|
||||
FROM sys_payment
|
||||
WHERE type = 0
|
||||
ORDER BY tenant_id;
|
||||
|
||||
-- 3. 插入示例微信支付配置(请根据实际情况修改)
|
||||
-- 注意:请将下面的值替换为您的实际配置
|
||||
/*
|
||||
INSERT INTO sys_payment (
|
||||
name,
|
||||
type,
|
||||
code,
|
||||
app_id,
|
||||
mch_id,
|
||||
api_key,
|
||||
merchant_serial_number,
|
||||
status,
|
||||
tenant_id,
|
||||
create_time,
|
||||
update_time
|
||||
) VALUES (
|
||||
'微信支付',
|
||||
0,
|
||||
'0',
|
||||
'wx1234567890abcdef', -- 请替换为您的微信小程序AppID
|
||||
'1723321338', -- 请替换为您的商户号
|
||||
'your_api_v3_key_here', -- 请替换为您的APIv3密钥
|
||||
'2B933F7C35014A1C363642623E4A62364B34C4EB', -- 请替换为您的商户证书序列号
|
||||
1,
|
||||
10550, -- 请替换为您的租户ID
|
||||
NOW(),
|
||||
NOW()
|
||||
) ON DUPLICATE KEY UPDATE
|
||||
app_id = VALUES(app_id),
|
||||
mch_id = VALUES(mch_id),
|
||||
api_key = VALUES(api_key),
|
||||
merchant_serial_number = VALUES(merchant_serial_number),
|
||||
update_time = NOW();
|
||||
*/
|
||||
|
||||
-- 4. 检查特定租户的支付配置
|
||||
-- SELECT * FROM sys_payment WHERE tenant_id = 10550 AND type = 0;
|
||||
|
||||
-- 5. 删除错误的支付配置(谨慎使用)
|
||||
-- DELETE FROM sys_payment WHERE id = ?;
|
||||
@@ -29,19 +29,31 @@ public class CertificateTest {
|
||||
public void testCertificateLoading() {
|
||||
try {
|
||||
System.out.println("=== 证书加载测试 ===");
|
||||
|
||||
|
||||
// 测试租户ID
|
||||
String tenantId = "10550";
|
||||
String tenantCertPath = "dev/wechat/" + tenantId;
|
||||
String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile();
|
||||
|
||||
|
||||
System.out.println("证书路径: " + privateKeyPath);
|
||||
System.out.println("加载模式: " + certConfig.getLoadMode());
|
||||
|
||||
System.out.println("开发环境证书路径前缀: " + certConfig.getDevCertPath());
|
||||
|
||||
// 检查证书文件是否存在
|
||||
boolean exists = certificateLoader.certificateExists(privateKeyPath);
|
||||
System.out.println("证书文件是否存在: " + exists);
|
||||
|
||||
if (!exists) {
|
||||
System.err.println("❌ 证书文件不存在: " + privateKeyPath);
|
||||
System.out.println("💡 请确认证书文件已放置在正确位置:");
|
||||
System.out.println(" src/main/resources/dev/wechat/10550/apiclient_key.pem");
|
||||
return;
|
||||
}
|
||||
|
||||
// 测试证书加载
|
||||
String privateKeyFile = certificateLoader.loadCertificatePath(privateKeyPath);
|
||||
System.out.println("私钥文件路径: " + privateKeyFile);
|
||||
|
||||
System.out.println("✅ 私钥文件加载成功: " + privateKeyFile);
|
||||
|
||||
// 测试自动证书配置
|
||||
System.out.println("=== 测试自动证书配置 ===");
|
||||
Config config = wechatCertAutoConfig.createAutoConfig(
|
||||
@@ -50,11 +62,45 @@ public class CertificateTest {
|
||||
"test-serial-number", // 测试序列号
|
||||
"test-api-key" // 测试API密钥
|
||||
);
|
||||
|
||||
System.out.println("自动证书配置创建成功: " + (config != null));
|
||||
|
||||
|
||||
System.out.println("✅ 自动证书配置创建成功");
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("证书测试失败: " + e.getMessage());
|
||||
System.err.println("❌ 证书测试失败: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotificationCertificateConfig() {
|
||||
try {
|
||||
System.out.println("=== 异步通知证书配置测试 ===");
|
||||
|
||||
// 模拟异步通知中的证书配置逻辑
|
||||
String tenantId = "10550";
|
||||
String tenantCertPath = "dev/wechat/" + tenantId;
|
||||
String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile();
|
||||
|
||||
System.out.println("租户ID: " + tenantId);
|
||||
System.out.println("证书目录: " + tenantCertPath);
|
||||
System.out.println("私钥路径: " + privateKeyPath);
|
||||
|
||||
// 检查证书文件是否存在
|
||||
if (!certificateLoader.certificateExists(privateKeyPath)) {
|
||||
System.err.println("❌ 证书文件不存在: " + privateKeyPath);
|
||||
throw new RuntimeException("证书文件不存在: " + privateKeyPath);
|
||||
}
|
||||
|
||||
String privateKey = certificateLoader.loadCertificatePath(privateKeyPath);
|
||||
String apiV3Key = certConfig.getWechatPay().getDev().getApiV3Key();
|
||||
|
||||
System.out.println("✅ 私钥文件加载成功: " + privateKey);
|
||||
System.out.println("APIv3密钥配置: " + (apiV3Key != null ? "已配置" : "未配置"));
|
||||
|
||||
System.out.println("✅ 异步通知证书配置测试通过");
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("❌ 异步通知证书配置测试失败: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.gxwebsoft.test;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* 异步通知证书修复验证测试
|
||||
*/
|
||||
public class NotificationCertificateFixTest {
|
||||
|
||||
@Test
|
||||
public void testCertificatePathFix() {
|
||||
System.out.println("=== 异步通知证书路径修复验证 ===");
|
||||
|
||||
// 模拟异步通知中的证书路径构建逻辑
|
||||
String tenantId = "10550";
|
||||
String devCertPath = "dev";
|
||||
String certDir = "wechat";
|
||||
String privateKeyFile = "apiclient_key.pem";
|
||||
|
||||
// 修复后的路径构建逻辑
|
||||
String tenantCertPath = devCertPath + "/" + certDir + "/" + tenantId;
|
||||
String privateKeyPath = tenantCertPath + "/" + privateKeyFile;
|
||||
|
||||
System.out.println("租户ID: " + tenantId);
|
||||
System.out.println("证书目录: " + tenantCertPath);
|
||||
System.out.println("私钥路径: " + privateKeyPath);
|
||||
|
||||
// 测试从classpath加载证书
|
||||
try {
|
||||
Resource resource = new ClassPathResource(privateKeyPath);
|
||||
System.out.println("证书资源存在: " + resource.exists());
|
||||
|
||||
if (resource.exists()) {
|
||||
// 模拟CertificateLoader.loadFromClasspath的逻辑
|
||||
Path tempFile = Files.createTempFile("cert_", ".pem");
|
||||
try (InputStream inputStream = resource.getInputStream()) {
|
||||
Files.copy(inputStream, tempFile, java.nio.file.StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
String tempPath = tempFile.toAbsolutePath().toString();
|
||||
System.out.println("✅ 证书加载成功: " + tempPath);
|
||||
|
||||
// 验证临时文件
|
||||
File tempCertFile = new File(tempPath);
|
||||
System.out.println("临时证书文件大小: " + tempCertFile.length() + " bytes");
|
||||
|
||||
// 清理临时文件
|
||||
Files.deleteIfExists(tempFile);
|
||||
|
||||
} else {
|
||||
System.err.println("❌ 证书文件不存在: " + privateKeyPath);
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
System.err.println("❌ 证书加载失败: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("=== 测试完成 ===");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllTenantCertificates() {
|
||||
System.out.println("=== 测试所有租户证书 ===");
|
||||
|
||||
String[] tenantIds = {"10398", "10550"};
|
||||
String devCertPath = "dev";
|
||||
String certDir = "wechat";
|
||||
String privateKeyFile = "apiclient_key.pem";
|
||||
|
||||
for (String tenantId : tenantIds) {
|
||||
System.out.println("\n--- 测试租户: " + tenantId + " ---");
|
||||
|
||||
String tenantCertPath = devCertPath + "/" + certDir + "/" + tenantId;
|
||||
String privateKeyPath = tenantCertPath + "/" + privateKeyFile;
|
||||
|
||||
System.out.println("证书路径: " + privateKeyPath);
|
||||
|
||||
try {
|
||||
Resource resource = new ClassPathResource(privateKeyPath);
|
||||
if (resource.exists()) {
|
||||
System.out.println("✅ 租户 " + tenantId + " 证书存在");
|
||||
} else {
|
||||
System.out.println("❌ 租户 " + tenantId + " 证书不存在");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("❌ 租户 " + tenantId + " 证书检查失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("\n=== 所有租户证书测试完成 ===");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package com.gxwebsoft.test;
|
||||
|
||||
import com.gxwebsoft.common.core.config.CertificateProperties;
|
||||
import com.gxwebsoft.common.core.utils.CertificateLoader;
|
||||
import com.gxwebsoft.common.core.utils.RedisUtil;
|
||||
import com.gxwebsoft.common.system.entity.Payment;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
|
||||
/**
|
||||
* 微信支付配置验证测试
|
||||
*/
|
||||
@SpringBootTest
|
||||
@ActiveProfiles("dev")
|
||||
public class WechatPayConfigValidationTest {
|
||||
|
||||
@Autowired
|
||||
private CertificateProperties certConfig;
|
||||
|
||||
@Autowired
|
||||
private CertificateLoader certificateLoader;
|
||||
|
||||
@Autowired
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
@Test
|
||||
public void testWechatPayConfigValidation() {
|
||||
System.out.println("=== 微信支付配置验证 ===");
|
||||
|
||||
// 1. 检查配置文件中的 APIv3 密钥
|
||||
String configApiV3Key = certConfig.getWechatPay().getDev().getApiV3Key();
|
||||
System.out.println("配置文件 APIv3 密钥: " + configApiV3Key);
|
||||
System.out.println("配置文件 APIv3 密钥长度: " + (configApiV3Key != null ? configApiV3Key.length() : 0));
|
||||
|
||||
// 2. 检查 Redis 中的支付配置
|
||||
String tenantId = "10550";
|
||||
String redisKey = "Payment:1:" + tenantId;
|
||||
Payment payment = redisUtil.get(redisKey, Payment.class);
|
||||
|
||||
if (payment != null) {
|
||||
System.out.println("\n=== Redis 支付配置 ===");
|
||||
System.out.println("商户号: " + payment.getMchId());
|
||||
System.out.println("应用ID: " + payment.getAppId());
|
||||
System.out.println("数据库 APIv3 密钥: " + payment.getApiKey());
|
||||
System.out.println("数据库 APIv3 密钥长度: " + (payment.getApiKey() != null ? payment.getApiKey().length() : 0));
|
||||
System.out.println("商户证书序列号: " + payment.getMerchantSerialNumber());
|
||||
|
||||
// 3. 比较两个 APIv3 密钥
|
||||
System.out.println("\n=== APIv3 密钥比较 ===");
|
||||
boolean keysMatch = (configApiV3Key != null && configApiV3Key.equals(payment.getApiKey()));
|
||||
System.out.println("配置文件与数据库密钥是否一致: " + keysMatch);
|
||||
|
||||
if (!keysMatch) {
|
||||
System.out.println("⚠️ 警告: 配置文件与数据库中的 APIv3 密钥不一致!");
|
||||
System.out.println("配置文件密钥: " + configApiV3Key);
|
||||
System.out.println("数据库密钥: " + payment.getApiKey());
|
||||
}
|
||||
|
||||
} else {
|
||||
System.out.println("❌ 未找到 Redis 中的支付配置: " + redisKey);
|
||||
|
||||
// 尝试其他可能的键格式
|
||||
String[] possibleKeys = {
|
||||
"Payment:1:10550",
|
||||
"Payment:0:10550",
|
||||
"Payment:10",
|
||||
"Payment:1" + "0" // Payment:10
|
||||
};
|
||||
|
||||
System.out.println("\n=== 尝试其他 Redis 键格式 ===");
|
||||
for (String key : possibleKeys) {
|
||||
Payment p = redisUtil.get(key, Payment.class);
|
||||
if (p != null) {
|
||||
System.out.println("✅ 找到支付配置: " + key);
|
||||
System.out.println(" 商户号: " + p.getMchId());
|
||||
System.out.println(" APIv3密钥: " + p.getApiKey());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 验证证书文件
|
||||
System.out.println("\n=== 证书文件验证 ===");
|
||||
String tenantCertPath = "dev/wechat/" + tenantId;
|
||||
String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile();
|
||||
|
||||
boolean certExists = certificateLoader.certificateExists(privateKeyPath);
|
||||
System.out.println("证书文件存在: " + certExists);
|
||||
System.out.println("证书路径: " + privateKeyPath);
|
||||
|
||||
if (certExists) {
|
||||
try {
|
||||
String privateKey = certificateLoader.loadCertificatePath(privateKeyPath);
|
||||
System.out.println("✅ 证书加载成功: " + privateKey);
|
||||
} catch (Exception e) {
|
||||
System.out.println("❌ 证书加载失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("\n=== 验证完成 ===");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApiV3KeyValidation() {
|
||||
System.out.println("=== APIv3 密钥格式验证 ===");
|
||||
|
||||
String configKey = certConfig.getWechatPay().getDev().getApiV3Key();
|
||||
|
||||
if (configKey != null) {
|
||||
System.out.println("APIv3 密钥: " + configKey);
|
||||
System.out.println("密钥长度: " + configKey.length());
|
||||
|
||||
// APIv3 密钥应该是32位字符串
|
||||
if (configKey.length() == 32) {
|
||||
System.out.println("✅ APIv3 密钥长度正确 (32位)");
|
||||
} else {
|
||||
System.out.println("❌ APIv3 密钥长度错误,应为32位,实际为: " + configKey.length());
|
||||
}
|
||||
|
||||
// 检查是否包含特殊字符
|
||||
boolean hasSpecialChars = !configKey.matches("^[a-zA-Z0-9]+$");
|
||||
if (hasSpecialChars) {
|
||||
System.out.println("⚠️ APIv3 密钥包含特殊字符,可能导致解密失败");
|
||||
} else {
|
||||
System.out.println("✅ APIv3 密钥格式正确 (仅包含字母和数字)");
|
||||
}
|
||||
|
||||
} else {
|
||||
System.out.println("❌ APIv3 密钥未配置");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user