微信支付v3签名通不过90%因字符串拼接不规范、编码非utf-8或时间戳/随机串不匹配;须严格按“方法\n路径\n时间戳\n随机串\n请求体sha256”五段换行拼接,再用pkcs#8私钥rsa-sha256签名。

微信支付 V3 签名生成失败:GenerateSignature 怎么写才对
签名通不过,90% 是因为没严格按 V3 规则拼接字符串、没用 UTF-8 编码、或时间戳/随机串没对齐。V3 不是简单 HMAC-SHA256,它要求:HTTP 方法 + \n + 路径 + \n + 时间戳 + \n + 随机串 + \n + 请求体 SHA256(空请求体用空字符串),五段换行拼接后,再用商户私钥(PKCS#8 格式)做 RSA-SHA256 签名。
实操要点:
-
HttpClient发请求前必须自己算签名,不能依赖第三方 SDK 的“自动签名”——很多老 SDK 只支持 V2 - 时间戳必须用
DateTimeOffset.UtcNow.ToUnixTimeSeconds(),不是DateTime.Now或毫秒时间戳 - 随机串推荐用
Convert.ToBase64String(RandomNumberGenerator.GetBytes(16)),避免特殊字符和长度不一致 - 请求体(如 JSON)必须原样参与签名,不能格式化、不能带多余空格,且必须是 UTF-8 字节数组的 SHA256 哈希值(
SHA256.HashData(Encoding.UTF8.GetBytes(body))) - 私钥必须是 PKCS#8 格式(以
-----BEGIN PRIVATE KEY-----开头),不是 PKCS#1(-----BEGIN RSA PRIVATE KEY-----)。用 OpenSSL 转换:openssl pkcs8 -topk8 -inform PEM -in apiclient_key.pem -outform PEM -nocrypt
回调验签总失败:为什么 VerifySignature 返回 false
微信回调的 WECHATPAY-SIGNATURE、WECHATPAY-TIMESTAMP、WECHATPAY-NONCE、WECHATPAY-SERIAL 四个 header 必须全部提取,且 body 必须是原始未解析的字节流(不能先 ReadAsStringAsync() 再转 byte[],会破坏换行和编码)。
验签逻辑关键点:
- 验签字符串拼接顺序是:
时间戳 + \n + 随机串 + \n + 响应体(原始字节流的 UTF-8 字符串) + \n,注意末尾那个\n容易漏 - 证书序列号(
WECHATPAY-SERIAL)要用来查本地缓存的平台公钥;首次收到新序列号时,必须调用/v3/certificates接口下载并验证证书链,不能硬编码 - 验签用的是微信平台公钥(RSA),不是你的商户私钥;公钥需从证书中提取:
RSA.ImportFromPem(publicKeyPem),不能直接用X509Certificate2.GetRSAPublicKey()(.NET Core 3.1+ 才安全) - 回调 body 必须用
HttpContext.Request.Body同步读取一次,读完重置 position,否则后续模型绑定会失败
使用 HttpClient 调用微信接口时,如何管理证书和超时
V3 接口强制 HTTPS,且必须双向认证(客户端证书),但微信只要求上传商户证书(apiclient_cert.p12),不校验服务端证书链。别在 HttpClientHandler 里设 ServerCertificateCustomValidationCallback 去忽略证书错误——这反而会让微信拒绝连接。
由于微信的大热,为了更好的方便使用微信的用户查询一些信息,这篇文章是入门级的微信公众平台开发教程,需要的朋友可以参考下 这篇入门教程将引导你完成如下任务: 创建百度云平台应用启用微信公众平台开发模式获取订阅、文字、图片、语音、视频消息回复文本、图文及音乐消息程序开发
正确做法:
- 把
apiclient_cert.p12加载为X509Certificate2,密码不能为空字符串(微信导出时若没设密码,填 " " 一个空格) -
HttpClientHandler.ClientCertificates.Add(cert)后,必须设置HttpClientHandler.SslProtocols = SslProtocols.Tls12,微信不支持 TLS 1.0/1.1 - 超时建议设为 25 秒(微信文档要求),用
new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(25) },不要用CancellationToken替代 - 不要复用同一个
HttpClient实例去发不同商户的请求——证书是绑定到 handler 的,混用会导致签名错乱
NotifyResult 返回 200 却仍被重复回调:怎么幂等处理
微信回调不保证只推一次,200 响应后网络中断也会触发重试。不能只靠数据库 INSERT IGNORE 或唯一索引挡——订单可能已创建但支付状态未更新。
可靠幂等方案:
- 回调解析出
resource.algorithm、resource.ciphertext、resource.nonce、resource.associated_data后,先解密得到原始通知(AES-GCM),再从中提取out_trade_no和transaction_id - 用
out_trade_no查库,如果订单已存在且status == "SUCCESS",直接返回成功;如果不存在或状态非终态,再走完整支付结果处理流程 - 解密失败、验签失败、字段缺失等异常,一律返回 401 或 500,微信会重试;返回 200 仅表示“我收到了,且业务上认可这次通知”
- 强烈建议加 Redis 分布式锁:
SET lock:out_trade_no:{outTradeNo} 1 EX 30 NX,防止集群下并发处理同一笔订单
最常被忽略的一点:微信回调 body 是加密的,你必须先解密才能拿到真实交易数据——跳过解密直接查 out_trade_no,等于没做验签,也拿不到真实金额和状态。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










