|
|
@@ -100,33 +100,44 @@ CREATE TABLE virtual_goods_config (
|
|
|
### 5.1 签名算法(官方参考脚本同款)
|
|
|
|
|
|
```java
|
|
|
-// paySig = to_hex(hmac_sha256(appKey, uri + "&" + signData))
|
|
|
-// uri 固定为 "requestVirtualPayment"(wx.requestVirtualPayment 场景)
|
|
|
-// signData = orderInfo + extInfo 按官方规则拼接(实现时对照官方 Python 脚本输出做断言单测)
|
|
|
+// paySig = to_hex(hmac_sha256(appKey, "requestVirtualPayment&" + signData))
|
|
|
+// signature = to_hex(hmac_sha256(sessionKey, signData)) // sessionKey 直接字符串编码,不 base64 解码
|
|
|
+// signData = orderInfo 的 JSON 串(LinkedHashMap 插入序序列化,与前端 JSON.stringify(orderInfo) 逐字节一致)
|
|
|
String paySig = HmacUtils.hmacSha256Hex(appKey, "requestVirtualPayment&" + signData);
|
|
|
```
|
|
|
|
|
|
+> ⚠️ 修正(2026-08-03):signData 必须是 **JSON 串**(非字典序 key=value 拼接),且 paySig/signature 都基于**同一** JSON 串(前端实际发送的 signData),否则微信验签报 -15005。
|
|
|
+
|
|
|
### 5.2 后端下单返回体 `VirtualPayParamsDTO`
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"orderInfo": {
|
|
|
- "mch_id": "虚拟支付商户号",
|
|
|
- "appid": "wx5ba8038ef16fb245",
|
|
|
- "out_trade_no": "A20260802xxx",
|
|
|
- "total_fee": 9900,
|
|
|
- "product_info": "五维测评·基础版",
|
|
|
+ "offerId": "1450607643",
|
|
|
+ "buyQuantity": 1,
|
|
|
+ "env": 0,
|
|
|
+ "currencyType": "CNY",
|
|
|
+ "productId": "member1314",
|
|
|
+ "goodsPrice": 131400,
|
|
|
+ "outTradeNo": "A20260802xxx",
|
|
|
"attach": "assessment:12"
|
|
|
},
|
|
|
"extInfo": {},
|
|
|
"sign": "paySig值",
|
|
|
+ "signature": "用户身份签名",
|
|
|
"env": 0,
|
|
|
"signType": "HMAC-SHA256"
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-- `total_fee` 单位:分,**以服务端计算为准**(防篡改)
|
|
|
-- `attach` 透传业务信息(goodsType:bizKey),便于对账
|
|
|
+- **orderInfo 为官方 `wx.requestVirtualPayment` signData 固定结构(camelCase),字段集不得增删:**
|
|
|
+ - `offerId`:**支付应用ID**(mp-虚拟支付基本配置,全应用唯一)——**不是道具ID**
|
|
|
+ - `productId`:**道具ID**(如 member1314),仅 `mode=short_series_goods` 必填
|
|
|
+ - `goodsPrice`:道具单价(分),官方校验与后台道具价格一致(金额以服务端计算为准,防篡改)
|
|
|
+ - `buyQuantity`:道具直购恒为 1
|
|
|
+ - `attach`:透传业务信息(goodsType:bizKey),发货推送时透传,便于对账
|
|
|
+ - `mode`:顶层参数(前端传 `short_series_goods`),**不在 signData 内**
|
|
|
+- ⚠️ 前端 `signData` 必须 = `JSON.stringify(orderInfo)`(保持插入序),与后端签名串逐字节一致,否则 -15005
|
|
|
- `env`:0=现网 1=沙箱,由配置 `wechat.virtual-pay-env` 控制
|
|
|
|
|
|
### 5.3 三个业务下单接口改造
|
|
|
@@ -178,10 +189,13 @@ String paySig = HmacUtils.hmacSha256Hex(appKey, "requestVirtualPayment&" + signD
|
|
|
```yaml
|
|
|
wechat:
|
|
|
appkey: ${WECHAT_APPKEY:} # 虚拟支付 AppKey(商户后台基本配置获取,现网/沙箱分开)
|
|
|
+ sandbox-appkey: ${WECHAT_SANDBOX_APPKEY:} # 虚拟支付沙箱 AppKey
|
|
|
+ offer-id: ${WECHAT_VIRTUAL_PAY_OFFER_ID:1450607643} # 支付应用ID(mp-支付基础配置;productId 才是道具ID)
|
|
|
virtual-pay-env: ${WECHAT_VIRTUAL_PAY_ENV:0} # 0=现网 1=沙箱
|
|
|
+ virtual-pay-token: ${WECHAT_VIRTUAL_PAY_TOKEN:cfcVirtualPay2026} # 消息推送 Token
|
|
|
```
|
|
|
|
|
|
-同步更新 `config/application.yml`(模板)与 `config/application-prod.yml`(生产覆盖)。
|
|
|
+> `config/application*.yml` 模板不在仓库内,服务器部署用环境变量注入。
|
|
|
|
|
|
## 9. 前端改动
|
|
|
|