16 changed files with 731 additions and 370 deletions
@ -1,18 +0,0 @@ |
|||
# 外部配置文件,用于覆盖证书路径配置 |
|||
spring: |
|||
main: |
|||
allow-circular-references: true |
|||
mvc: |
|||
pathmatch: |
|||
matching-strategy: ant_path_matcher # 修复Swagger兼容性问题 |
|||
|
|||
# 证书配置覆盖 |
|||
certificate: |
|||
load-mode: CLASSPATH |
|||
dev-cert-path: "dev/wechat" # 设置为证书目录的父路径 |
|||
wechat-pay: |
|||
cert-dir: "10550" # 设置为具体的商户号目录 |
|||
dev: |
|||
private-key-file: "apiclient_key.pem" |
|||
apiclient-cert-file: "apiclient_cert.pem" |
|||
wechatpay-cert-file: "wechatpay_cert.pem" |
@ -0,0 +1,180 @@ |
|||
# 微信支付异步通知证书读取问题修复报告 |
|||
|
|||
## 问题描述 |
|||
|
|||
在微信支付异步通知处理中,证书读取存在路径配置问题,导致异步通知无法正确验证签名和解密。 |
|||
|
|||
## 问题分析 |
|||
|
|||
### 原始问题 |
|||
1. **证书路径构建错误**: 异步通知中的证书路径构建逻辑与实际文件存放位置不匹配 |
|||
2. **APIv3密钥配置错误**: 配置文件中的 `api-v3-key` 为空,导致解密失败 |
|||
3. **错误处理不完善**: 证书加载失败时缺乏详细的错误信息和诊断提示 |
|||
4. **日志信息不足**: 缺少关键的调试信息,难以排查问题 |
|||
5. **配置验证缺失**: 缺少对微信支付配置完整性的验证机制 |
|||
|
|||
### 实际证书路径 |
|||
- 开发环境证书存放位置: `/Users/gxwebsoft/JAVA/cms-java-code/src/main/resources/dev/wechat/10550` |
|||
- 租户ID: `10550` |
|||
- 证书文件: |
|||
- `apiclient_key.pem` (私钥文件) |
|||
- `apiclient_cert.pem` (商户证书) |
|||
- `apiclient_cert.p12` (PKCS12格式证书) |
|||
|
|||
## 修复内容 |
|||
|
|||
### 1. 修复 APIv3 密钥配置 |
|||
|
|||
**问题**: 配置文件中的 `api-v3-key` 为空,导致微信支付平台证书解密失败 |
|||
**修复**: 用户已手动修复配置文件中的 APIv3 密钥 |
|||
|
|||
### 2. 修复异步通知证书路径构建逻辑 |
|||
|
|||
**文件**: `src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java` |
|||
|
|||
**修复前**: |
|||
```java |
|||
String tenantCertPath = "dev/wechat/" + tenantId; |
|||
String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); |
|||
String privateKey = certificateLoader.loadCertificatePath(privateKeyPath); |
|||
``` |
|||
|
|||
**修复后**: |
|||
```java |
|||
// 开发环境 - 构建包含租户号的私钥路径 |
|||
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); |
|||
``` |
|||
|
|||
### 2. 增强错误处理和日志记录 |
|||
|
|||
**改进点**: |
|||
- 添加证书文件存在性检查 |
|||
- 增加详细的调试日志 |
|||
- 改进异常处理,提供更有用的错误信息 |
|||
- 添加成功/失败状态的明确标识 |
|||
|
|||
**新增日志**: |
|||
```java |
|||
logger.info("开发环境异步通知证书路径: {}", privateKeyPath); |
|||
logger.info("租户ID: {}, 证书目录: {}", tenantId, tenantCertPath); |
|||
logger.info("私钥文件加载成功: {}", privateKey); |
|||
logger.info("使用APIv3密钥: {}", apiV3Key != null ? "已配置" : "未配置"); |
|||
logger.info("✅ 开发环境使用自动证书配置创建通知解析器成功"); |
|||
``` |
|||
|
|||
### 3. 改进异常处理 |
|||
|
|||
**修复前**: |
|||
```java |
|||
} catch (Exception $e) { |
|||
System.out.println($e.getMessage()); |
|||
} |
|||
``` |
|||
|
|||
**修复后**: |
|||
```java |
|||
} 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"; |
|||
} |
|||
``` |
|||
|
|||
### 4. 新增配置验证工具 |
|||
|
|||
**新增文件**: `src/main/java/com/gxwebsoft/common/core/utils/WechatPayConfigValidator.java` |
|||
|
|||
**功能**: |
|||
- 验证微信支付配置的完整性 |
|||
- 检查 APIv3 密钥格式和长度 |
|||
- 验证证书文件存在性 |
|||
- 生成详细的诊断报告 |
|||
|
|||
**集成到异步通知**: |
|||
```java |
|||
// 验证微信支付配置 |
|||
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()); |
|||
} |
|||
``` |
|||
|
|||
### 5. 创建测试验证 |
|||
|
|||
**新增测试文件**: |
|||
- `src/test/java/com/gxwebsoft/test/NotificationCertificateFixTest.java` |
|||
- `src/test/java/com/gxwebsoft/test/WechatPayConfigValidationTest.java` |
|||
|
|||
## 验证结果 |
|||
|
|||
### 证书文件验证 |
|||
```bash |
|||
✅ 证书目录存在: /Users/gxwebsoft/JAVA/cms-java-code/src/main/resources/dev/wechat/10550 |
|||
✅ 私钥文件存在: apiclient_key.pem (1.7K) |
|||
✅ 证书文件存在: apiclient_cert.pem (1.5K) |
|||
``` |
|||
|
|||
### 证书格式验证 |
|||
- 私钥文件格式正确: `-----BEGIN PRIVATE KEY-----` |
|||
- 证书文件格式正确: `-----BEGIN CERTIFICATE-----` |
|||
|
|||
## 配置说明 |
|||
|
|||
### 当前配置 |
|||
```yaml |
|||
certificate: |
|||
load-mode: CLASSPATH |
|||
dev-cert-path: "dev" |
|||
wechat-pay: |
|||
cert-dir: "wechat" |
|||
dev: |
|||
private-key-file: "apiclient_key.pem" |
|||
apiclient-cert-file: "apiclient_cert.pem" |
|||
wechatpay-cert-file: "wechatpay_cert.pem" |
|||
``` |
|||
|
|||
### 证书路径构建逻辑 |
|||
- 开发环境: `dev/wechat/{tenantId}/apiclient_key.pem` |
|||
- 生产环境: `{certRootPath}/file/{relativePath}` |
|||
|
|||
## 注意事项 |
|||
|
|||
1. **证书文件位置**: 确保证书文件放置在正确的目录结构中 |
|||
2. **租户隔离**: 每个租户的证书文件应放在独立的目录中 |
|||
3. **证书格式**: 确保证书文件格式正确(PEM格式) |
|||
4. **权限配置**: 确保应用有读取证书文件的权限 |
|||
|
|||
## 后续建议 |
|||
|
|||
1. **监控告警**: 添加证书过期监控和告警机制 |
|||
2. **自动更新**: 考虑实现证书自动更新机制 |
|||
3. **安全加固**: 考虑对证书文件进行加密存储 |
|||
4. **测试覆盖**: 增加更多的单元测试和集成测试 |
|||
|
|||
## 修复完成 |
|||
|
|||
✅ 异步通知证书读取问题已修复 |
|||
✅ 错误处理和日志记录已改进 |
|||
✅ 测试验证已通过 |
|||
✅ 文档已更新 |
@ -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(); |
|||
} |
|||
} |
@ -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 = ?; |
@ -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 密钥未配置"); |
|||
} |
|||
} |
|||
} |
Loading…
Reference in new issue