微信支付商户证书

微信支付 APIv3 要求使用商户证书进行身份验证和敏感信息加解密,配置流程比 APIv2 复杂不少。本文整理从申请到后端集成的完整步骤。

证书体系概述

微信支付 APIv3 涉及两类证书:

证书类型作用来源
商户 API 证书请求签名,证明你的商户身份商户平台自行申请
平台证书验证微信支付回调签名,加密敏感数据微信侧提供,需程序自动下载更新

简单来说:你发请求用商户证书,收回调验平台证书。

步骤一:申请商户 API 证书

  1. 登录 微信支付商户平台
  2. 进入 账户中心 → API安全 → API证书
  3. 点击「申请证书」,按提示下载证书生成工具
  4. 使用工具生成 CSR 文件并提交
  5. 获取证书文件,通常包含:
    • apiclient_key.pem — 商户私钥
    • apiclient_cert.pem — 商户证书

步骤二:设置 APIv3 密钥

APIv3 需要一个 32 位密钥用于平台证书解密和回调验签:

  1. 进入 账户中心 → API安全 → APIv3密钥
  2. 点击「设置」,生成或填写 32 位随机字符串
  3. 妥善保存此密钥,丢失后无法找回,只能重置
1
2
# 推荐用命令生成随机32位密钥
openssl rand -hex 16

步骤三:后端集成

安装依赖

以 Node.js 为例:

1
npm install wechatpay-node-v3

基础配置

1
2
3
4
5
6
7
8
9
10
11
import WechatPay from 'wechatpay-node-v3';
import fs from 'fs';

const wechatPay = new WechatPay({
appid: 'wx1234567890',
mchid: '1234567890',
publicKey: fs.readFileSync('/path/to/apiclient_cert.pem'),
privateKey: fs.readFileSync('/path/to/apiclient_key.pem'),
// APIv3 密钥
secretKey: 'your-32-char-api-v3-key',
});

发起支付请求示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// JSAPI 下单
const result = await wechatPay.transactions_jsapi({
description: '98潮玩 - 游戏礼包',
out_trade_no: 'ORDER20240718001',
notify_url: 'https://yyimg.com/api/wxpay/notify',
amount: {
total: 1, // 单位:分
currency: 'CNY',
},
payer: {
openid: 'oUpF8xxxxxxxxxxxx',
},
});

console.log(result.prepay_id); // 传给前端调起支付

回调验签

收到微信支付的异步通知时,必须验证签名:

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
import { Controller, Post, Body, Headers } from '@midwayjs/core';

@Controller('/api/wxpay')
export class WxPayController {

@Post('/notify')
async notify(
@Headers('wechatpay-signature') signature: string,
@Headers('wechatpay-timestamp') timestamp: string,
@Headers('wechatpay-nonce') nonce: string,
@Headers('wechatpay-serial') serial: string,
@Body() body: any
) {
// 验证签名
const verified = wechatPay.verifySignature(signature, timestamp, nonce, body);
if (!verified) {
return { code: 'FAIL', message: '签名验证失败' };
}

// 解密通知数据
const resource = body.resource;
const decrypted = wechatPay.decipher(resource.ciphertext, resource.associated_data, resource.nonce);

console.log('支付成功:', decrypted);

// 处理业务逻辑...
return { code: 'SUCCESS', message: 'OK' };
}
}

平台证书自动更新

平台证书有有效期(通常 1 年),到期前需要更新。务必在代码中实现自动下载:

1
2
3
4
5
6
7
8
9
10
11
12
// 初始化时自动下载最新平台证书
await wechatPay.initPlatformCertificate();

// 建议配合定时任务定期刷新
setInterval(async () => {
try {
await wechatPay.initPlatformCertificate();
console.log('平台证书已刷新');
} catch (err) {
console.error('平台证书刷新失败:', err);
}
}, 12 * 60 * 60 * 1000); // 每12小时检查一次

常见问题

1. 证书路径在服务器上找不到

生产环境建议用环境变量配置路径,避免硬编码:

1
2
3
4
5
const wechatPay = new WechatPay({
// ...
privateKey: fs.readFileSync(path.join(__dirname, process.env.WXPAY_KEY_PATH || '')),
publicKey: fs.readFileSync(path.join(__dirname, process.env.WXPAY_CERT_PATH || '')),
});

2. 回调验签失败

常见原因:

  • 平台证书过期,检查 wechatpay-serial 请求头中的序列号
  • POST body 被中间件解析后变成对象,验签前需转为原始 JSON 字符串
  • 使用了错误的 APIv3 密钥

3. APIv2 迁移到 APIv3

如果你还在用 APIv2:

  • APIv3 不再需要证书文件进行签名,改用私钥签名
  • 敏感信息(如用户手机号)从明文改为密文,需要解密
  • 回调通知格式完全不同,数据结构是加密的 JSON

4. 环境隔离

正式环境和沙箱环境的证书独立,不要混用:

1
2
3
4
5
6
7
8
const isProd = process.env.NODE_ENV === 'production';
const config = isProd ? {
mchid: '真实商户号',
// ... 真实证书
} : {
mchid: '沙箱商户号',
// ... 沙箱证书
};

总结

微信支付 APIv3 证书配置的核心步骤:

  1. 商户平台申请 API 证书(apiclient_cert.pem + apiclient_key.pem)
  2. 设置 32 位 APIv3 密钥
  3. 后端集成 SDK,实现签名和验签
  4. 实现平台证书自动更新,避免过期导致回调失败
  5. 做好环境隔离和错误处理

搞定这些,微信支付的证书问题基本不会再困扰你。