微信支付报错:无可用平台证书 解决方案

Caret Up

前言

最近在接微信支付的时候,遇到了一个 无可用平台证书 的报错,记录下解决过程。

经过一番查找,发现这个问题是由于平台证书存在过期时间,需要开发这由于没有及时更换,会导致支付失败。 因为在 v3 接口中,微信强制只允许使用公钥进行验签。而相关的报错信息模糊,没有明显的公告,加上官方 给出的示例也没有更新到使用公钥的版本,导致接入的时候在这个问题上浪费了不少时间。

名词解释

商户id、商户号(mcnId)

微信支付平台 - 账户中心 - 商户信息 - 基本账户信息 - 微信支付商户号

证书序列号(SerialNumber,SerialNo)

微信支付平台 - 账户中心 - API安全 - API 证书管理 - 证书序列号

也可以使用命令行查看

1
openssl x509 -in apiclient_cert.pem -noout -serial

私钥需要下载工具生成。具体位置为 微信支付平台 - 账户中心 - API 安全 - API 证书管理

APIv3 Key

APIv2 已经停止支持,使用 v3 即可

微信支付平台 - 账户中心 - API安全 - 解密回调 - APIv3 密钥(自己设置的32位字符)

公钥、公钥ID

微信支付平台 - 账户中心 - API安全 - 微信支付公钥

  • 可重新下载公钥
  • 可直接复制公钥 ID

SDK调整

官方提供的 SDK

github.com/wechatpay-apiv3/wechatpay-go v0.2.20

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package main

import (
	"context"

	"github.com/rs/zerolog/log"
	"github.com/wechatpay-apiv3/wechatpay-go/core"
	"github.com/wechatpay-apiv3/wechatpay-go/core/option"
	"github.com/wechatpay-apiv3/wechatpay-go/utils"
)

func main() {
	ctx := context.Background()
	mchId := "xxx"           // 商户号
	mchCertSerialNo := "xxx" // 商户证书序列号
	publicKeyId := "xxx"     // 公钥ID

	// 载入私钥
	mchPrivateKey, err := utils.LoadPrivateKeyWithPath("xxx_key.pem")
	if err != nil {
		log.Fatal().Err(err).Msg("load private key failed")
	}

	// 载入公钥
	mchPublicKey, err := utils.LoadPublicKeyWithPath("xxx.pem")
	if err != nil {
		log.Fatal().Err(err).Msg("load public key failed")
	}

	// 初始化客户端
	opts := []core.ClientOption{
		option.WithWechatPayPublicKeyAuthCipher(mchId, mchCertSerialNo, mchPrivateKey, publicKeyId, mchPublicKey),
	}

	client, err := core.NewClient(ctx, opts...)
	if err != nil {
		log.Error().Err(err).Msg("init client failed")
	}

	_ = client
}

第三方 SDK (go-pay)

github.com/go-pay/gopay v1.5.109

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import (
	"github.com/go-pay/gopay"
	"github.com/go-pay/gopay/wechat/v3"
	"github.com/rs/zerolog/log"
)

func main(){
	client, err := wechat.NewClientV3(mchId, mchCertificateSerialNumber, mchAPIv3Key, mchPrivateKeyStr)
	if err != nil {
		log.Fatal().Err(err).Msg("init client failed")
	}
	// 需要使用公钥解密
	err = client.AutoVerifySignByCert(mchPublicKey, publicKeyId)
	if err != nil {
		log.Fatal().Err(err).Msg("init client failed")
	}
	client.DebugSwitch = gopay.DebugOn
}

参考