rswxpay
纯 Rust 实现的微信支付 V3 API SDK。不依赖 OpenSSL,所有加密操作均使用纯 Rust 实现。
功能
- JSAPI / Native / H5 / App 四种支付方式下单
- 订单查询(商户订单号 / 微信交易号)、关闭订单
- 申请退款、退款查询
- 交易账单、资金账单下载
- 支付回调通知验签与解密(交易通知 / 退款通知)
- 平台证书自动下载与缓存(12 小时自动刷新)
- 小程序 / App 调起支付参数签名
- 敏感字段(私钥、API v3 密钥)内存安全清零
依赖
| 功能 | 依赖 | 说明 |
|---|---|---|
| 异步运行时 | tokio |
async/await 支持 |
| HTTP 客户端 | reqwest |
rustls-tls,纯 Rust TLS |
| 请求签名/验签 | rsa |
PKCS1v15 + SHA256 |
| 通知解密 | aes-gcm |
AES-256-GCM |
| 证书解析 | x509-cert |
X.509 证书 DER/PEM 解析 |
| 序列化 | serde + serde_json |
JSON 序列化/反序列化 |
| 内存安全 | zeroize |
敏感字段销毁时清零 |
快速开始
添加依赖
[]
= "0.1"
= { = "1", = ["full"] }
= "1"
初始化客户端
use ;
let config = builder
.mch_id // 商户号
.serial_no // 商户 API 证书序列号
.api_v3_key // API v3 密钥(32 字节 ASCII)
.private_key_pem // 商户私钥(PKCS1 或 PKCS8)
.build?;
let client = new.await?;
ClientConfig::builder() 还支持以下可选配置:
builder
.mch_id
.serial_no
.api_v3_key
.private_key_pem
.base_url // 自定义 API 地址(默认值如左)
.http_client // 自定义 reqwest::Client
.build?;
JSAPI 下单示例
use ;
use ;
use JsapiPrepayRequest;
async
API 参考
下单
// JSAPI(小程序/公众号)
let resp = client.jsapi_prepay.await?;
// resp: JsapiPrepayResponse { prepay_id: String }
// Native(扫码支付)
let resp = client.native_prepay.await?;
// resp: NativePrepayResponse { code_url: String }
// H5
let resp = client.h5_prepay.await?;
// resp: H5PrepayResponse { h5_url: String }
// App
let resp = client.app_prepay.await?;
// resp: AppPrepayResponse { prepay_id: String }
四种下单请求结构大致相同,必填字段:
| 字段 | 类型 | 说明 |
|---|---|---|
appid |
String |
应用 ID |
mchid |
String |
商户号 |
description |
String |
商品描述 |
out_trade_no |
String |
商户订单号 |
notify_url |
String |
回调通知地址 |
amount |
Amount |
订单金额(total 单位:分) |
JSAPI 额外必填 payer: Payer { openid },H5 额外必填 scene_info: SceneInfo。
调起支付参数签名
// 小程序 / JSAPI — 返回 JsapiPayParams
let params = client.build_jsapi_pay_params?;
// App — 返回 AppPayParams
let params = client.build_app_pay_params?;
返回的参数可直接序列化为 JSON 传给前端/客户端调起支付。
订单查询与关闭
// 通过商户订单号查询
let order = client.query_order_by_out_trade_no.await?;
// 通过微信交易号查询
let order = client.query_order_by_transaction_id.await?;
// 关闭订单(返回 (),HTTP 204)
client.close_order.await?;
OrderQueryResponse 主要字段:
| 字段 | 类型 | 说明 |
|---|---|---|
trade_state |
String |
交易状态:SUCCESS / REFUND / NOTPAY / CLOSED / ... |
trade_state_desc |
String |
状态描述 |
transaction_id |
Option<String> |
微信支付订单号 |
amount |
Option<OrderAmount> |
金额信息(含 total、payer_total) |
payer |
Option<Payer> |
支付者信息 |
退款
use ;
// 申请退款
let refund = client.create_refund.await?;
// 查询退款
let refund = client.query_refund.await?;
RefundResponse 主要字段:
| 字段 | 类型 | 说明 |
|---|---|---|
refund_id |
String |
微信退款单号 |
status |
String |
退款状态:SUCCESS / PROCESSING / ABNORMAL / CLOSED |
channel |
String |
退款渠道 |
user_received_account |
String |
退款入账账户 |
账单下载
use ;
// 获取交易账单下载地址
let bill = client.get_trade_bill.await?;
// 获取资金账单下载地址
let bill = client.get_fund_flow_bill.await?;
// 下载账单文件(返回 bytes::Bytes)
let data = client.download_bill.await?;
回调通知
从 HTTP 请求头中提取验签所需字段,然后解析通知内容:
use NotifyHeaders;
let headers = NotifyHeaders ;
// 解析交易通知
let tx = client.parse_transaction_notify.await?;
// tx: TransactionNotify { appid, mchid, out_trade_no, transaction_id, trade_state, ... }
// 解析退款通知
let refund = client.parse_refund_notify.await?;
// refund: RefundNotify { mchid, out_trade_no, out_refund_no, refund_status, ... }
通知处理流程:验签 -> 时间戳新鲜度检查(±5 分钟) -> AES-256-GCM 解密 -> JSON 反序列化。
错误处理
所有公开方法返回 Result<T, WxPayError>。WxPayError 定义如下:
| 变体 | 说明 |
|---|---|
Http(reqwest::Error) |
HTTP 请求失败 |
Api { code, message, detail } |
微信支付 API 返回的业务错误 |
SignError(String) |
签名失败 |
VerifyError(String) |
验签失败 |
DecryptError(String) |
解密失败 |
InvalidKey(String) |
密钥格式错误 |
CertError(String) |
证书相关错误 |
Serialize(serde_json::Error) |
JSON 序列化/反序列化错误 |
Config(String) |
配置错误 |
NotifyError(String) |
通知处理错误 |
match client.jsapi_prepay.await
模块结构
src/
├── lib.rs 公开导出(WxPayClient, ClientConfig, WxPayError)
├── client.rs WxPayClient — 签名 HTTP 请求 + 响应验签
├── config.rs ClientConfig + Builder 模式
├── error.rs WxPayError 错误枚举
├── notify.rs 回调通知验签与解密
├── crypto/
│ ├── sign.rs 请求签名(SHA256withRSA + PKCS1v15)
│ ├── verify.rs 响应验签(RSA 公钥验证)
│ └── decrypt.rs AES-256-GCM 解密(通知/证书)
├── cert/
│ ├── store.rs 平台证书内存缓存(HashMap + RwLock)
│ └── manager.rs 证书自动下载与 12 小时刷新
├── api/
│ ├── prepay.rs 下单(JSAPI / Native / H5 / App)
│ ├── order.rs 订单查询 / 关闭
│ ├── refund.rs 退款申请 / 查询
│ └── bill.rs 账单下载
└── model/
├── common.rs 公共类型(Amount, Payer, SceneInfo 等)
├── prepay.rs 下单请求/响应 + 调起支付参数
├── order.rs 订单查询响应
├── refund.rs 退款请求/响应
├── bill.rs 账单请求/响应
├── notify.rs 通知信封 + 解密后数据类型
└── cert.rs 证书接口响应
安全设计
- 纯 Rust 加密 — 不依赖 OpenSSL,使用
rsa、aes-gcm、x509-cert纯 Rust 实现 - 强制响应验签 — fail-closed 策略,证书存储非空时缺少签名头即报错
- 通知验签 — 验签 + 时间戳新鲜度检查(±5 分钟窗口),防重放攻击
- AES-GCM AAD — 解密使用附加认证数据,防篡改
- 内存安全清零 —
ClientConfig销毁时自动清零api_v3_key和private_key_pem - 密钥校验 —
api_v3_key强制 32 字节 ASCII 校验 - URL 编码 — 路径参数全部 percent-encoding,防注入
- 非阻塞签名 — RSA 签名使用
spawn_blocking,避免阻塞 tokio 异步运行时
构建与测试
License
MIT