feat(weibo): 增加微博微豆基础自动化

This commit is contained in:
yml2213
2026-11-07 20:33:15 +08:00
parent 16196332f2
commit b7f34df04d
21 changed files with 4989 additions and 1 deletions
@@ -0,0 +1,696 @@
---
type: 协议确认
description: 微博微豆自动化唯一协议,覆盖 CK 登录态、微信/QQ 绑定二维码、助力充值、支付二维码、微豆明细、商城列表、兑换和兑换记录。
tags: [微博, 微豆, VPlus, 助威, 充值, 兑换, 微信小程序, QQ小程序, URL Scheme, 二维码, CK]
generated:
by: ai/codex
at: 2026-11-07T19:03:41+08:00
status: stable
verified:
- { by: ai/codex, at: 2026-11-07T19:03:41+08:00 }
---
# 微博微豆 CK 接口与兑换链路确认
确认日期:2026-11-07
原始样本:用户提供的 `充值1元-查询明细-兑换列表-兑换1天会员.har`。该 HAR 含账号 Cookie、用户标识、昵称和支付数据,不纳入仓库。
## 1. 结论
微博业务接口只需要微博登录 Cookie(下文简称 CK),未观察到独立的 access token、CSRF token 或客户端签名 Header。绑定二维码转换接口 `GenMiniappScheme` 不需要微博、微信或 QQ 的账号 Cookie,但仍依赖微博链接内层的 `code`、`nonce`、`sig`、`t` 业务参数。
核心链路:
```text
CK + F
-> GET /aj/mall/home 获取用户、绑定状态、余额、任务、商城入口
|
+-> 未绑定:game_role.bind_url
| -> POST GenMiniappScheme
| -> 微信/QQ urlScheme
| -> 生成绑定二维码
|
+-> 助威得微豆:
GET /aj/vmember/gfsupport 获取助力目标 uid/vuid
GET /aj/paycomponent/cashierinfo 获取收银台、商品档位、活动参数
POST /aj/paycomponent/createorder 创建充值订单
打开 data.url,读取收银台 HTML 中的支付二维码
POST /aj/pay/status 轮询支付状态
GET /aj/point/get_point_recharge_history 查询微豆获取明细
|
+-> 微豆兑换:
GET /aj/mall/list 查询商城列表与余额
GET /aj/mall/detail 查询商品详情
GET /aj/game/exchangegoods 执行兑换
GET /aj/mall/list 复核余额和库存
GET /aj/mall/exchange 查询兑换记录
```
## 2. 共同会话与 Header
### 2.1 必需状态
- 微博 CK:必需。实测不带 Cookie 时:
- `/aj/mall/home` 返回 `code=400002`、`msg=未登陆`。
- `/aj/point/get_point_recharge_history` 返回 `code=400000`、`msg=user not login`。
- `F`:活动来源标识。样本为 `bowen_tjg`,应作为活动入口参数配置,不要推导算法。
- `uid`:微博用户 ID,从 `/aj/vmember/gfsupport`、收银台响应或页面状态获取。
- `vuid`:被助威的 V+ 账号 ID,从 `/vmember/subscribe` URL、`task_list.action_url` 或对应接口获取。
CK 是否可缩减为只有 `SUB` 尚未验证。样本请求中同时出现 `SUB`、`SUBP`、`SCF`、`ALF`、`PC_TOKEN`、`v!pay` 等 Cookie,建议先维护完整 Cookie Jar,再逐步做最小化测试。
### 2.2 请求头
样本未观察到:
- `Authorization`
- `X-CSRF-Token`
- 自定义签名 Header
- 客户端加密 Body
GET 请求至少携带:
```http
Cookie: <微博 CK>
Referer: <对应页面 URL>
```
POST 请求使用:
```http
Content-Type: application/x-www-form-urlencoded
Origin: https://vipclub.weibo.com
Referer: https://vipclub.weibo.com/vmember/subscribe?...
Cookie: <微博 CK>
```
前端每个 GET 请求都会自动追加毫秒时间戳:
```text
_t=<Date.now()>
```
`_t` 是缓存破坏参数,未观察到参与签名。
## 3. 用户、绑定和任务入口
```http
GET https://vipclub.e.weibo.com/aj/mall/home?F=<F>&_t=<毫秒时间戳>
```
关键响应字段:
| 字段 | 含义 |
| --- | --- |
| `data.user_info.uid` | 当前登录微博 uid |
| `data.game_role.is_bound` | 是否已绑定游戏角色 |
| `data.game_role.role_name` | 已绑定角色 |
| `data.game_role.bind_url` | 微博小程序绑定链接 |
| `data.game_role.can_rebind` | 当前是否允许换绑 |
| `data.game_role.rebind_remain_days` | 下次可换绑的剩余天数 |
| `data.weidou_balance.balance` | 当前微豆余额 |
| `data.task_list` | 微豆任务列表 |
| `data.recommend_list` | 推荐商品 |
| `data.mall_url` | 商城入口 |
### 3.1 微信/QQ 绑定二维码
本次 HAR 的状态是:
```json
{
"is_bound": true,
"can_rebind": false
}
```
因此本次没有重新走绑定动作。页面逻辑是:
- `is_bound=false`:展示“绑定角色”,点击后打开 `game_role.bind_url`。
- `is_bound=true && can_rebind=true`:进入换绑。
- `is_bound=true && can_rebind=false`:前端直接提示剩余天数,不打开链接。
`bind_url` 形如:
```text
sinaweibo://wbdiversion?username=<username>&path=<encoded-path>
```
输入也可能直接来自其他微博小程序跳转:
```text
sinaweibo://wbdiversion?username=gh_<username>&path=/pages/gameAccountBind/index?<inner_query>
```
其中:
- `username=gh_...` 是微博侧小程序标识,不传给来联接口。
- `sinaweibo://wbdiversion` 只用于微博客户端唤起,不传给来联接口。
- `<inner_query>` 是 `path=/pages/gameAccountBind/index?` 后面的全部原始 Query。
实测内层业务参数包括:
```text
actId
code
faceUrl
gameId
gameIdList
livePlatId
nickName
nonce
sig
t
v
```
必须保留原始百分号编码。不要先 `URLDecoder`、`parse_qs` 或重新拼 Query,否则 `code`、`faceUrl` 中的多重编码可能被改变。
#### 3.1.1 生成微信/QQ URL Scheme
页面入口是:
```text
https://livelink.qq.com/h5-open-mp/wx?<inner_query>
https://livelink.qq.com/h5-open-mp/qq?<inner_query>
```
PC 页面不会直接展示二维码,而是请求:
```http
POST https://livelinkbind.game.qq.com/livelink?c=Sdk&a=GenMiniappScheme&<path内层参数>
Content-Type: application/json
```
微信请求体:
```json
{"accountType":"wx"}
```
QQ 请求体:
```json
{"accountType":"qq"}
```
成功响应:
```json
{
"iRet": 0,
"sMsg": "ok",
"jData": {
"urlScheme": "<小程序 URL Scheme>"
},
"v": 2,
"apiName": "GenMiniappScheme"
}
```
二维码必须编码 `jData.urlScheme` 的完整字符串,不应编码原 `livelink.qq.com` 页面地址。
#### 3.1.2 Scheme 格式
微信:
```text
weixin://dl/business/?appid=wx707e2eb408780a5b&path=pages/gameAccountBind/index&query=scheme_id%3D<dynamic>
```
QQ:
```text
mqqapi://miniapp/open?_atype=0&_mappid=1111906964&_miniapptype=1&_mvid=&_path=pages%2FgameAccountBind%2Findex&_vt=3&via=qq_txyxll&_sig=<dynamic>&_nq=<encoded-inner-query>
```
本次样本确认:
| 字段 | 微信 | QQ |
| --- | --- | --- |
| 小程序 AppID | `wx707e2eb408780a5b` | `1111906964` |
| 页面路径 | `pages/gameAccountBind/index` | `pages/gameAccountBind/index` |
| 动态凭证 | `scheme_id` | `_sig`、`_nq` 内的业务参数 |
| 二维码内容 | 返回的 `urlScheme` | 返回的 `urlScheme` |
AppID、路径和渠道字段只代表本次活动样本;业务参数不能写死为常量。
#### 3.1.3 鉴权与时效
`GenMiniappScheme` 实测只发送:
```http
Content-Type: application/json
```
没有发送:
- 微博 Cookie
- 微信/QQ Cookie
- Bearer Token
- 微信/QQ access token
- 微信/QQ OAuth 回调参数
- 用户登录会话
微信和 QQ 两个请求均返回 HTTP 200、`iRet=0`,响应没有 `Set-Cookie`。
这里的“不需要鉴权”只表示 Scheme 生成接口不依赖账号登录态。`code`、`nonce`、`sig`、`t` 仍是来联业务的防篡改和时效参数,不能删除或改写。
- `t` 是 Unix 秒时间戳。
- `scheme_id` 和 QQ `_sig` 由服务端动态生成。
- 样本在 `t` 后约 54 分钟仍可生成 Scheme,但不足以确定固定 TTL。
- 每次都应从新的微博链接或新的 `bind_url` 提取内层 Query,不能长期缓存。
微信页面在“微信内直接唤起小程序”的分支会调用 `/api/common/getWxJsApiTicket` 配置 `wx-open-launch-weapp`;该 JS-SDK 分支不是二维码生成链路,二维码生成不需要它。
本次没有抓到 `is_bound=false` 的独立样本,因此未绑定场景下 `bind_url` 的值仍需下一次抓包确认;但当前已绑定响应中同样存在 `bind_url`,且同一 `GenMiniappScheme` 链路已实测可用。
## 4. 助威得微豆与充值
### 4.1 助威入口
`/aj/mall/home` 的 `task_list` 样本中包含:
```json
{
"title": "助威得微豆",
"button_type": "cashier",
"action_url": "sinaweibo://transparentbrowser?url=<encoded-subscribe-url>"
}
```
解码后进入:
```text
https://vipclub.weibo.com/vmember/subscribe?vuid=<vuid>&source_itemid=20601&F=<F>
```
### 4.2 获取助力目标
```http
GET https://vipclub.weibo.com/aj/vmember/gfsupport?vuid=<vuid>&source_itemid=20601&F=<F>&_t=<ms>
```
响应提供:
- `data.uid`
- `data.vuid`
- `data.u_name`
- 被助威账号信息
- 是否已助力/会员
### 4.3 获取收银台和商品档位
```http
GET https://vipclub.weibo.com/aj/paycomponent/cashierinfo
?F=<F>
&tab_id=536
&cashier_id=205
&cashier_version=0.2.3
&vuid=<vuid>
&source_itemid=20601
```
页面输入还包含空值参数:
```text
appName=&from=&wm=&profileuid=&device_id=&tab_type=&bid=
```
这些空参数可以保留以贴合浏览器行为,尚未逐一测试是否可省略。
关键响应:
```text
data.cashier_id
data.tab_info[].tab_id
data.tab_info[].tab_type
data.tab_info[].menu[]
data.user_info.uid
```
样本“1 元 = 100 微豆”档位:
| 字段 | 值 |
| --- | --- |
| `commodity_id` | `2060101` |
| `subitemid` | `2060101` |
| `itemid` | `20601` |
| `appkey` | `2000` |
| `cashier_id` | `205` |
| `tab_type` | `8` |
| `max_money` | `1000` |
| `discount_info.desc` | `1元=100微豆` |
页面允许自定义 1–1000 元,提交时把金额换算成:
```text
single_reward = 金额(元) * 100
```
所以 1 元对应 `single_reward=100`。
### 4.4 创建充值订单
```http
POST https://vipclub.weibo.com/aj/paycomponent/createorder?<与 Body 相同的业务参数>
Content-Type: application/x-www-form-urlencoded
Origin: https://vipclub.weibo.com
Referer: https://vipclub.weibo.com/vmember/subscribe?vuid=<vuid>&source_itemid=20601&F=<F>
Cookie: <微博 CK>
```
样本核心 Body:
```text
subitemid=2060101
itemid=20601
appkey=2000
commodity_id=2060101
num=1
cashier_id=205
F=<F>
is_from_cashier=1
cashierpw=1
vuid=<vuid>
tab_type=8
cashier_version=0.2.3
single_reward=100
ext={"bid":"<bid>","send_blog":1}
```
其他样本字段:
```text
salestrategy_id=
discount_id=
from=
device_id=
level_up_tag=0
to_uid=
return_url=
ori_t_id=
will_auto_renew=0
subpw=
account=
follow=false
coupon_id=
gc=
bid=
mid=
```
浏览器前端拦截器会把同一组参数同时放进 URL Query 和 form Body。样本服务端接受了这种重复传参。实现时建议保持 Query + Body 一致,除非后续实测证明只传 Body 也可以。
样本 Body 中还有 `is_eligible=undefined`,这是前端直接序列化未定义值产生的字符串,不应作为可靠业务参数。
成功响应关键字段:
| 字段 | 含义 |
| --- | --- |
| `data.url` | 微博支付收银台 URL |
| `data.orderid` | 支付订单号,后续微豆明细的 `source_id` |
| `data.pay_return_url` | 支付完成后的业务回跳地址 |
| `data.return_url` | 带订单号的回跳地址 |
| `data.channel` | 样本为 `weibo_web` |
### 4.5 支付收银台和二维码
使用同一 Cookie 打开 `data.url`,经过:
```text
GET /api/merchant/pay/cashier
-> 302 /pay/pc/cashier
-> 200 收银台 HTML
```
收银台 HTML 内直接包含支付信息:
```html
<input type="hidden" name="pay_id" value="<pay_id>">
<img node-type="QRCode" src="https://qr.weibo.cn/inf/gen?...">
<a href="https://pay.sc.weibo.com/pay/pc/comb?pay_id=<pay_id>...">立即支付</a>
```
支付二维码由收银台服务端生成带 `api_key`、`data`、`sign` 的 `qr.weibo.cn/inf/gen` URL。客户端不需要自行计算该签名,按 HTML 解析即可。
### 4.6 支付状态轮询
```http
POST https://pay.sc.weibo.com/aj/pay/status
Content-Type: application/x-www-form-urlencoded
X-Requested-With: XMLHttpRequest
Origin: https://pay.sc.weibo.com
Referer: <收银台 URL>
Cookie: <微博 CK>
pay_id=<pay_id>&ispage=1&_t=0
```
样本状态:
```text
code=100000
data.status=PAY_STATUS_PENDING
data.sub_status=PAY_SUB_STATUS_INITIAL
```
样本约每 1 秒轮询一次,共 16 次待支付状态;用户在支付宝扫码并完成支付后,流程跳转成功页。支付动作本身属于外部支付流程,不应由 CK 自动完成或绕过。
### 4.7 到账确认
支付完成后再次请求 `/aj/mall/home`:
```text
data.weidou_balance.balance = 100
```
微豆明细出现:
```json
{
"source_type": 101,
"record_type": 208681,
"source_id": "<createorder.data.orderid>",
"source_name": "V+助威",
"point_num": 100
}
```
本次充值 1 元,到账 100 微豆。
### 4.8 `pay/modular/prepare`
样本还出现:
```http
POST https://pay.sc.weibo.com/aj/pay/modular/prepare
```
请求体是页面初始“超能爆发”档位的 `total_amount=6000`,响应为空。本次 1 元自定义订单没有从该响应读取任何字段,实际下单依赖的是 `/aj/paycomponent/createorder`。暂不把它列入 1 元充值必需链路。
## 5. 微豆明细
```http
GET https://vipclub.e.weibo.com/aj/point/get_point_recharge_history
?F=<F>
&page_no=1
&page_size=20
&_t=<ms>
```
响应:
```text
data.page_num
data.page_size
data.total
data.list[]
data.expire_remind
```
样本明细:
| 字段 | 含义 |
| --- | --- |
| `id` | 明细 ID |
| `source_type` | 来源类型,样本为 `101` |
| `record_type` | 记录类型,样本为 `208681` |
| `source_id` | 支付订单号 |
| `source_name` | 来源名,样本为 `V+助威` |
| `point_num` | 到账微豆,样本为 `100` |
| `create_time` | 到账时间 |
| `expire_time` | 微豆过期时间 |
该接口从名称和样本看是“微豆获取/充值明细”。兑换消耗记录使用 `/aj/mall/exchange`,不要把两个接口混为一谈。
## 6. 微豆商城列表
```http
GET https://vipclub.e.weibo.com/aj/mall/list?F=<F>&_t=<ms>
```
响应:
```text
data.list[]
data.weidou_balance
data.exchange_url
```
商品字段:
```text
id
goods_name
goods_image
price
remain_count
is_sold_out
goods_desc
```
本次抓包中的商品 ID:
| goods_id | 商品 | 价格/微豆 |
| --- | --- | ---: |
| 21 | 汪仔布丁大礼包 | 28000 |
| 22 | 套装-暮夜私语 | 9880 |
| 23 | 套装-墨青刃影 | 7880 |
| 12 | 套装-暗影哥特 | 8880 |
| 14 | 套装-浪漫天命 | 3600 |
| 13 | 黑色高级特训官上衣 | 3600 |
| 18 | 幸运币礼包(小) | 200 |
| 19 | 幸运币礼包(中) | 3000 |
| 20 | 幸运币礼包(大) | 9000 |
| 15 | 荣耀勋章礼包(小) | 200 |
| 16 | 荣耀勋章礼包(中) | 3000 |
| 17 | 荣耀勋章礼包(大) | 9000 |
| 42 | 微博VIP年卡 | 10800 |
| 41 | 微博VIP月卡 | 1000 |
| 40 | 微博VIP周卡 | 400 |
| 39 | 微博会员5天卡 | 300 |
| 38 | 微博会员3天卡 | 200 |
| 37 | 微博会员1天卡 | 100 |
`remain_count` 是实时库存,不能写成常量。
## 7. 商品详情与兑换
### 7.1 商品详情
```http
GET https://vipclub.e.weibo.com/aj/mall/detail?F=<F>&goods_id=<goods_id>&_t=<ms>
```
响应包含:
```text
goods_info
weidou_balance
payment_button
nickname
game_nickname
```
只有 `payment_button.clickable=true` 且 `payment_button.type=exchange` 时,前端才允许兑换。
### 7.2 执行兑换
```http
GET https://vipclub.e.weibo.com/aj/game/exchangegoods?F=<F>&goods_id=<goods_id>&_t=<ms>
```
请求参数只有 `F`、`goods_id`、`_t`,没有额外确认 Token。
成功响应:
```json
{
"code": 100000,
"msg": "success",
"data": null
}
```
样本兑换 `goods_id=37`(微博会员1天卡)后再次请求 `/aj/mall/list`:
- `data.weidou_balance` 从 `100` 变为 `0`;
- goods 37 的 `remain_count` 从 `4639` 变为 `4638`。
因此 `code=100000` 表示请求成功,但仍应刷新商城列表确认余额和库存变化。
注意:这是使用 GET 执行状态变更的接口。不能做自动重试、并发点击或把一次成功当成幂等。
### 7.3 兑换记录
```http
GET https://vipclub.e.weibo.com/aj/mall/exchange
?F=<F>
&page=1
&page_size=20
&_t=<ms>
```
响应:
```text
data.page
data.pageSize
data.list
data.totalCount
```
本次在兑换前查询两次,结果均为空列表。兑换后没有再请求该接口,因此兑换成功后的记录字段仍需补抓一次。
## 8. 同一页面的辅助接口
以下接口出现在页面加载流程中,但不是上述业务的必需前置:
| 接口 | 用途 |
| --- | --- |
| `/aj/paycomponent/userinfo` | 获取收银台 tab |
| `/aj/paycomponent/couponlist` | 优惠券状态 |
| `/aj/strategy/info` | 活动策略提示 |
| `/aj/paycomponent/privilege` | V+ 权益展示 |
| `/actionlog` | 前端埋点 |
## 9. 实现约束
1. 所有微博业务接口都依赖与目标用户一致的 Cookie;先验证 `/aj/mall/home` 返回 `code=100000`。
2. 使用 Cookie Jar,保留响应和收银台页面产生的 Cookie 更新。
3. `_t` 使用当前毫秒时间,不复用抓包值。
4. `uid`、`vuid`、`cashier_id`、`tab_id`、`itemid`、`appkey` 和 `single_reward` 来自页面响应,业务代码只保留活动配置。
5. 充值金额以 `single_reward` 为准:1 元填 `100`。
6. 兑换接口是 GET 状态变更,必须设置本地防重锁并禁止自动重试。
7. 支付二维码从 `createorder.data.url` 对应的收银台 HTML 中解析,不要重新计算 `qr.weibo.cn` 的 `sign`。
8. 不记录或回显完整 Cookie、支付 URL、二维码短链、uid、vuid、昵称和订单号。
## 10. 鉴权与错误处理
已确认:
- 没有独立业务 Token;CK 是核心认证状态。
- 没有观察到 CSRF Header 或请求签名算法。
- 未登录时接口会返回 `400002`、`400000` 或跳转微博登录页。
建议处理:
| code | 处理 |
| --- | --- |
| `100000` | 成功 |
| `100002` | 登录失效,停止任务并要求更新 CK |
| `100004` | 进入微博错误页,停止任务 |
| `400002` | `未登陆`,CK 无效 |
| `400000` | `user not login`,CK 无效 |
| 其他 | 保留服务端 `msg` 和 `trace_id`,不要盲目重试状态变更接口 |
## 11. 尚未确认
- 是否只需要 `SUB`,还是必须完整 Cookie Jar。
- 本次未抓 `is_bound=false` 的绑定响应。
- 本次未抓兑换后的 `/aj/mall/exchange` 记录。
- `/aj/game/exchangegoods` 在余额不足、重复兑换、角色未绑定时的错误码。
- 支付订单在支付宝侧取消、超时、退款后的业务状态。
- 各活动的 `F`、`itemid`、`source_itemid`、`cashier_id`、`tab_id` 是否跨活动变化;实现时应从页面动态读取。