Skip to content

微信支付 v3 的证书和密钥,四类东西别再配混了

接微信支付 v3,商户平台上要拿四类东西:APIv3 密钥、API 证书、商户证书序列号、微信支付公钥。

落到配置文件里,这四类会摊成八个字段。网上大部分教程只讲了其中两三个,剩下的等你签名失败的时候自己撞。

踩错的代价

这几样配错,报错长得都一样:SIGN_ERROR,HTTP 401,"签名验证失败"。

它不会告诉你是私钥错了、序列号错了、还是公钥拿反了。八个变量,一个错误码。

更难受的是它不是必现。下单接口能通,回调解密失败——因为下单用的是商户私钥签名,回调用的是 APIv3 密钥解密,两套东西。你以为配好了,钱收不到才发现。

别逐个字段试,按环节反推

八个字段一个个换着试,是最慢的排查方式。按失败发生在哪个环节,能直接圈到某一类上

失败发生在说明这几个是对的问题只可能在
下单请求就被拒(401)——商户私钥、证书序列号、商户号
下单成功,拿到 prepay_id私钥、序列号、商户号都对——
收到回调但解密失败签名那套全对只可能是 APIv3 密钥
解密出来了但验签不过密钥也对微信支付公钥 / 公钥 ID

下单成功这件事本身就是一个强信号:它证明签名那一套(私钥 + 序列号 + 商户号)全对,剩下的问题不可能在那三个上面。

很多人卡住是因为一看到"签名失败"就把八个字段全怀疑一遍。先看走到哪一步断的,一次能排掉一半。

先分清方向:签名和验签不是同一把钥匙

配之前先把方向理清楚,后面八个字段就不会乱。

签名和验签是两个相反的方向,用的是两套不同的钥匙:

我方 → 微信微信 → 我方
动作给请求签名验证响应和回调的签名
用什么商户 API 私钥(apiclient_key.pem微信支付公钥
标识商户证书序列号公钥 ID

回调报文的解密是第三件事,跟上面两个方向都无关,用 APIv3 密钥。

三件事、三套东西,混在一起就是各种"签名失败"。

四类东西分别是什么

一、APIv3 密钥(32 位)

在商户平台的「API 安全」页面里设置(账户中心下面),自己定的 32 位字符串。

用途只有两个:解密回调报文(AES-256-GCM)、下载平台证书。

最常见的坑:跟 v2 的「API 密钥」搞混。 商户平台上这是两个独立入口,都是 32 位,都叫密钥。v2 那个做 MD5/HMAC 签名,v3 这个做解密,互相不通用。设置页面还挨在一起。

这个坑不是"不小心",是结构性的——后面配置那节你会看到,代码里 mchKeyapiV3Key 就是两个独立字段,摆着两个坑位等你填错。

二、API 证书(两个文件)

同一个页面申请下载,解压后你要的是两个:

  • apiclient_key.pem —— 商户 API 私钥,签名用它
  • apiclient_cert.pem —— 商户证书,序列号从它里面读

这个只能下载一次,重新申请会作废旧的。生产环境的证书丢了就是重新申请,中间这段时间收不到钱。

路径用相对路径或从配置注入,不要写绝对路径。 本地跑通了传到服务器上找不到文件,这个坑我在部署那批文章里写过一次。

三、商户证书序列号

从证书里读:

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

输出形如 serial=1A2B3C...,去掉 serial= 前缀,转成大写填进配置。

「API 安全」页面上也能直接看到,两边应该一致。不一致说明你手里的证书不是当前生效的那张——大概率是重新申请过,本地还留着旧的。

四、微信支付公钥 —— 这里 2024 年之后变了

这是全文最容易过时的一节,也是最多人配错的一节。

新申请的商户号:直接在商户平台下载「微信支付公钥」,配一个公钥文件加一个公钥 ID(形如 PUB_KEY_ID_...)。静态的,不会变。

老商户号:还是平台证书模式。平台证书不能在页面上直接下载,要用工具或调接口拿,拿的时候还得用 APIv3 密钥解密。

平台证书模式有个隐藏的坑:证书会轮换。微信提前一段时间下发新证书,旧的到期作废。如果你把平台证书硬编码进代码、或者只在启动时加载一次,某天会突然全线验签失败,而你什么都没改。

官方 SDK 里有自动更新平台证书的实现,别自己写。

落到配置里,实际是八个字段

前面四类,摊到配置文件是这八个。这张表是我配的时候最想要、但网上找不到的东西

配置字段是什么去哪拿
appId小程序或公众号 AppID小程序/公众号后台
mchId商户号商户平台首页
apiV3KeyAPIv3 密钥(32 位)「API 安全」页面,自己设
certSerialNo商户证书序列号openssl 从证书读,或「API 安全」页看
privateCertPathapiclient_cert.pem 路径申请证书时下载
privateKeyPathapiclient_key.pem 路径同上,同一个压缩包
publicKeyPath微信支付公钥文件路径商户平台下载
publicKeyId公钥 ID(PUB_KEY_ID_...跟公钥一起给的

配置写出来是这样:

yaml
wxpay:
  # 小程序或公众号的 AppID —— 注意不是商户号
  app-id: wx**********
  mch-id: 16**********
  # APIv3 密钥,32 位。不是 v2 的那个 API 密钥
  api-v3-key: ********************************
  # 商户证书序列号,大写,从 apiclient_cert.pem 读出来
  cert-serial-no: 1A2B3C**********
  # 相对路径,别写绝对路径,换环境会找不到
  private-cert-path: cert/apiclient_cert.pem
  private-key-path: cert/apiclient_key.pem
  # 微信支付公钥模式(新商户号)
  public-key-path: cert/pub_key.pem
  public-key-id: PUB_KEY_ID_**********

配完自己核一遍:证书序列号和商户平台页面上显示的一致,这一条能挡掉一半的签名失败。

还有三个字段不属于 v3,但最容易顺手填错

翻配置的时候你还会看到这几个,它们不是 v3 要的

  • mchKey —— v2 的 API 密钥。跟 apiV3Key 长得一样都是 32 位,填串了就是签名失败
  • keyPath —— v2 的 p12 证书,老版本退款用的
  • subAppId / subMchId —— 服务商模式才用。你是普通商户就留空,填了反而报错

最后这对我单独说一句:服务商模式是另一套玩法(分账、子商户),跟普通商户号的配置不通用。看到配置里有这两个字段不代表你需要填。 什么时候才该上服务商模式,我另外写。

常见报错对照表

报错真正的原因怎么查
SIGN_ERROR / 401 签名验证失败certSerialNo 或商户私钥不对openssl 重新读一次序列号,跟商户平台核对,注意大写
下单成功,回调解密报错apiV3Key 填成了 v2 的 mchKey回「API 安全」页确认是哪个入口的密钥
验签失败,但签名没问题公钥拿反了,或用商户证书去验签确认验签用的是微信那边的公钥,不是自己的
昨天还好好的,今天全部验签失败平台证书轮换了换成 SDK 的自动更新,或迁到公钥模式
本地通,服务器 500,找不到文件证书用了绝对路径改相对路径或从配置注入
提示子商户号错误普通商户填了 subMchId服务商模式才用,普通商户留空
NO_AUTH不是签名问题,是商户号没签约这个产品商户平台的「产品中心」确认 JSAPI/APP 支付已开通

签名-A

大粽子