diff --git a/jituan/management/commands/wx_v3_pay_diag.py b/jituan/management/commands/wx_v3_pay_diag.py index eca748e..2497a0e 100644 --- a/jituan/management/commands/wx_v3_pay_diag.py +++ b/jituan/management/commands/wx_v3_pay_diag.py @@ -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}')) diff --git a/jituan/services/wechat_pay.py b/jituan/services/wechat_pay.py index d85f9cb..1bd7422 100644 --- a/jituan/services/wechat_pay.py +++ b/jituan/services/wechat_pay.py @@ -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: