fix: 证书扫描含pub_key.pem;诊断明确缺少apiclient_cert.pem

服务器仅有私钥无商户证书时V3签名必失败,诊断输出操作指引。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-10 22:33:24 +08:00
parent b5021ee07d
commit 6ac32674a5
2 changed files with 37 additions and 14 deletions

View File

@@ -50,20 +50,41 @@ class Command(BaseCommand):
try:
private_key = _load_pem_private_key(key_path)
self.stdout.write('private_key : 加载成功')
cert_path = key_path.replace('apiclient_key.pem', 'apiclient_cert.pem')
if os.path.isfile(cert_path):
from cryptography import x509
from cryptography.hazmat.backends import default_backend
with open(cert_path, 'rb') as f:
cert = x509.load_pem_x509_certificate(f.read(), default_backend())
matched = _public_keys_match(private_key, cert.public_key())
self.stdout.write(
f"apiclient_cert.pem 与私钥匹配: {matched} "
f"serial={format(cert.serial_number, 'X').upper()}"
)
else:
from cryptography import x509
from cryptography.hazmat.backends import default_backend
tested = []
for fname in sorted(os.listdir(cert_dir)):
if not fname.lower().endswith('.pem'):
continue
if fname.lower() in ('apiclient_key.pem',):
continue
cert_path = os.path.join(cert_dir, fname)
tested.append(fname)
try:
with open(cert_path, 'rb') as f:
data = f.read()
if b'PRIVATE KEY' in data:
self.stdout.write(f' {fname}: 是私钥,跳过')
continue
cert = x509.load_pem_x509_certificate(data, default_backend())
serial = format(cert.serial_number, 'X').upper()
matched = _public_keys_match(private_key, cert.public_key())
self.stdout.write(
f' {fname}: X509证书 serial={serial} 与私钥匹配={matched}'
)
except Exception as exc:
self.stdout.write(f' {fname}: 非X509商户证书 ({exc})')
if 'apiclient_cert.pem' not in tested:
self.stdout.write(self.style.ERROR(
f'缺少 apiclient_cert.pem(与 apiclient_key.pem 同目录): {cert_path}'
'\n缺少 apiclient_cert.pem'
'\n请到微信商户平台(1747846572) → 账户中心 → API安全 → 申请API证书'
'\n下载证书包,将 apiclient_cert.pem 放到目录:'
f'\n {cert_dir}'
'\n当前目录只有 apiclient_key.pem没有商户证书所以签名必然失败。'
'\npub_key.pem 是微信支付平台公钥,不能代替 apiclient_cert.pem。'
))
except Exception as exc:
self.stdout.write(self.style.ERROR(f'私钥/证书检查失败: {exc}'))

View File

@@ -87,7 +87,9 @@ def resolve_merchant_cert_serial(private_key_path, configured_serial=''):
for fname in sorted(os.listdir(cert_dir)):
if not fname.lower().endswith('.pem'):
continue
if 'key' in fname.lower():
lower = fname.lower()
# 只跳过私钥文件pub_key.pem 等仍尝试(有人误命名证书)
if lower in ('apiclient_key.pem',) or 'private' in lower:
continue
candidates.append(os.path.join(cert_dir, fname))
except OSError as exc: