2 changed files with 298 additions and 17 deletions
@ -0,0 +1,222 @@ |
|||
package com.gxwebsoft.common.core.utils; |
|||
|
|||
import com.gxwebsoft.common.system.entity.Payment; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import java.io.File; |
|||
import java.nio.file.Files; |
|||
import java.nio.file.Paths; |
|||
|
|||
/** |
|||
* 微信支付配置诊断工具 |
|||
* 用于排查微信支付签名验证失败等问题 |
|||
* |
|||
* @author 科技小王子 |
|||
* @since 2025-07-27 |
|||
*/ |
|||
@Slf4j |
|||
@Component |
|||
public class WechatPayDiagnostic { |
|||
|
|||
/** |
|||
* 诊断微信支付配置 |
|||
* |
|||
* @param payment 支付配置 |
|||
* @param privateKeyPath 私钥路径 |
|||
* @param environment 环境标识 |
|||
*/ |
|||
public void diagnosePaymentConfig(Payment payment, String privateKeyPath, String environment) { |
|||
log.info("=== 微信支付配置诊断开始 ==="); |
|||
log.info("环境: {}", environment); |
|||
|
|||
// 1. 检查支付配置基本信息
|
|||
checkBasicConfig(payment); |
|||
|
|||
// 2. 检查证书文件
|
|||
checkCertificateFiles(payment, privateKeyPath, environment); |
|||
|
|||
// 3. 检查配置完整性
|
|||
checkConfigCompleteness(payment); |
|||
|
|||
log.info("=== 微信支付配置诊断结束 ==="); |
|||
} |
|||
|
|||
/** |
|||
* 检查基本配置信息 |
|||
*/ |
|||
private void checkBasicConfig(Payment payment) { |
|||
log.info("--- 基本配置检查 ---"); |
|||
|
|||
if (payment == null) { |
|||
log.error("❌ 支付配置为空"); |
|||
return; |
|||
} |
|||
|
|||
log.info("支付配置ID: {}", payment.getId()); |
|||
log.info("支付方式名称: {}", payment.getName()); |
|||
log.info("支付类型: {}", payment.getType()); |
|||
log.info("支付代码: {}", payment.getCode()); |
|||
log.info("状态: {}", payment.getStatus()); |
|||
|
|||
// 检查关键字段
|
|||
checkField("应用ID", payment.getAppId()); |
|||
checkField("商户号", payment.getMchId()); |
|||
checkField("商户证书序列号", payment.getMerchantSerialNumber()); |
|||
checkField("API密钥", payment.getApiKey(), true); |
|||
} |
|||
|
|||
/** |
|||
* 检查证书文件 |
|||
*/ |
|||
private void checkCertificateFiles(Payment payment, String privateKeyPath, String environment) { |
|||
log.info("--- 证书文件检查 ---"); |
|||
|
|||
// 检查私钥文件
|
|||
if (privateKeyPath != null) { |
|||
checkFileExists("私钥文件", privateKeyPath); |
|||
} |
|||
|
|||
// 生产环境检查证书文件
|
|||
if (!"dev".equals(environment)) { |
|||
if (payment.getApiclientCert() != null) { |
|||
log.info("商户证书文件配置: {}", payment.getApiclientCert()); |
|||
} |
|||
|
|||
if (payment.getPubKey() != null) { |
|||
log.info("公钥文件配置: {}", payment.getPubKey()); |
|||
log.info("公钥ID: {}", payment.getPubKeyId()); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 检查配置完整性 |
|||
*/ |
|||
private void checkConfigCompleteness(Payment payment) { |
|||
log.info("--- 配置完整性检查 ---"); |
|||
|
|||
boolean isComplete = true; |
|||
|
|||
if (isEmpty(payment.getMchId())) { |
|||
log.error("❌ 商户号未配置"); |
|||
isComplete = false; |
|||
} |
|||
|
|||
if (isEmpty(payment.getMerchantSerialNumber())) { |
|||
log.error("❌ 商户证书序列号未配置"); |
|||
isComplete = false; |
|||
} |
|||
|
|||
if (isEmpty(payment.getApiKey())) { |
|||
log.error("❌ API密钥未配置"); |
|||
isComplete = false; |
|||
} |
|||
|
|||
if (isEmpty(payment.getAppId())) { |
|||
log.error("❌ 应用ID未配置"); |
|||
isComplete = false; |
|||
} |
|||
|
|||
if (isComplete) { |
|||
log.info("✅ 配置完整性检查通过"); |
|||
} else { |
|||
log.error("❌ 配置不完整,请补充缺失的配置项"); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 检查字段是否为空 |
|||
*/ |
|||
private void checkField(String fieldName, String value) { |
|||
checkField(fieldName, value, false); |
|||
} |
|||
|
|||
/** |
|||
* 检查字段是否为空 |
|||
*/ |
|||
private void checkField(String fieldName, String value, boolean isSensitive) { |
|||
if (isEmpty(value)) { |
|||
log.warn("⚠️ {}: 未配置", fieldName); |
|||
} else { |
|||
if (isSensitive) { |
|||
log.info("✅ {}: 已配置(长度:{})", fieldName, value.length()); |
|||
} else { |
|||
log.info("✅ {}: {}", fieldName, value); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 检查文件是否存在 |
|||
*/ |
|||
private void checkFileExists(String fileName, String filePath) { |
|||
try { |
|||
File file = new File(filePath); |
|||
if (file.exists() && file.isFile()) { |
|||
log.info("✅ {}: 文件存在 - {}", fileName, filePath); |
|||
log.info(" 文件大小: {} bytes", file.length()); |
|||
|
|||
// 检查文件内容格式
|
|||
if (filePath.endsWith(".pem")) { |
|||
checkPemFileFormat(fileName, filePath); |
|||
} |
|||
} else { |
|||
log.error("❌ {}: 文件不存在 - {}", fileName, filePath); |
|||
} |
|||
} catch (Exception e) { |
|||
log.error("❌ {}: 检查文件时出错 - {} ({})", fileName, filePath, e.getMessage()); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 检查PEM文件格式 |
|||
*/ |
|||
private void checkPemFileFormat(String fileName, String filePath) { |
|||
try { |
|||
String content = Files.readString(Paths.get(filePath)); |
|||
if (content.contains("-----BEGIN") && content.contains("-----END")) { |
|||
log.info("✅ {}: PEM格式正确", fileName); |
|||
} else { |
|||
log.warn("⚠️ {}: PEM格式可能有问题", fileName); |
|||
} |
|||
} catch (Exception e) { |
|||
log.warn("⚠️ {}: 无法读取文件内容进行格式检查 ({})", fileName, e.getMessage()); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 检查字符串是否为空 |
|||
*/ |
|||
private boolean isEmpty(String str) { |
|||
return str == null || str.trim().isEmpty(); |
|||
} |
|||
|
|||
/** |
|||
* 生成诊断报告 |
|||
*/ |
|||
public String generateDiagnosticReport(Payment payment, String environment) { |
|||
StringBuilder report = new StringBuilder(); |
|||
report.append("🔍 微信支付配置诊断报告\n"); |
|||
report.append("========================\n\n"); |
|||
|
|||
report.append("环境: ").append(environment).append("\n"); |
|||
report.append("租户ID: ").append(payment != null ? payment.getTenantId() : "未知").append("\n"); |
|||
report.append("商户号: ").append(payment != null ? payment.getMchId() : "未配置").append("\n"); |
|||
report.append("应用ID: ").append(payment != null ? payment.getAppId() : "未配置").append("\n\n"); |
|||
|
|||
report.append("🚨 常见问题排查:\n"); |
|||
report.append("1. 商户证书序列号是否正确\n"); |
|||
report.append("2. APIv3密钥是否正确\n"); |
|||
report.append("3. 私钥文件是否正确\n"); |
|||
report.append("4. 微信支付平台证书是否过期\n"); |
|||
report.append("5. 网络连接是否正常\n\n"); |
|||
|
|||
report.append("💡 建议解决方案:\n"); |
|||
report.append("1. 使用自动证书配置(RSAAutoCertificateConfig)\n"); |
|||
report.append("2. 在微信商户平台重新下载证书\n"); |
|||
report.append("3. 检查商户平台API安全设置\n"); |
|||
|
|||
return report.toString(); |
|||
} |
|||
} |
Loading…
Reference in new issue