feat: add Yuheng ticket bind, trial SMS off, shared bindings

Ship ticket-exchange and bind/policy for Z13, keep trial binds SMS-free, allow shared company bindings, and align SyncPage plus sync docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
whm
2026-08-05 15:09:49 +08:00
parent f90245db9c
commit d195aa4804
19 changed files with 957 additions and 96 deletions

View File

@@ -152,10 +152,57 @@ Content-Type: application/json
成功 → 智能体挂到该公司 + 默认同步落点,`sync_bound=true`
### 同号探测 / 确认Z13c / Z13c-1 · 硬约束
### 同号探测 / 确认Z13c / Z13c-1
**禁止静默绑定**。有手机号时必须先 lookup命中后**弹窗确认**再 confirm。
**推荐(仅宇恒 · 安全凭票免登录)**:用户已登录宇恒时,由**宇恒后端**用共享 Secret 签发短时凭票,客户端调:
```http
POST /api/v1/auth/yuheng/ticket-exchange
Content-Type: application/json
{
"ticket": "YHT1.<payload>.<hmac>",
"host_key": "<宿 key>",
"local_database_id": ""
}
```
成功直接返回智能体 `access_token` + `sync_bound` / `channel_id` / `online_db_id`**无需**智建账号密码,也**不要**再传 `attested_same_phone`)。
凭票 payloadJSONHMAC-SHA256前缀 `YHT1`)字段:
| 字段 | 说明 |
|------|------|
| `iss` | 固定 `yuheng` |
| `aud` | 固定 `aijianzhan` |
| `phone` | 宇恒当前已绑手机(须已是智建公司成员) |
| `host_key` | 与请求一致 |
| `exp` | Unix 秒;建议 60120s智建拒 >now+10m |
| `jti` | 一次性随机串(防重放) |
| `scope` | `sync_bind` |
| `name` / `local_database_id` | 可选 |
配置(智建 `platform.yaml``Agent.YuhengTicket``Enabled` + 与宇恒共享的 `Secret`。生产必换 Secret**其它客户端不得使用**。
启动前可拉策略(公开,无需登录):
```http
GET /api/v1/auth/bind/policy
```
| 字段 | 说明 |
|------|------|
| `trial_mode` | `true` = 试运行(不强制绑定短信) |
| `require_for_bind` | 是否强制短信(与 `SMS.RequireForBind` + Provider≠off 一致) |
| `yuheng_ticket_enabled` | 是否启用凭票换票 |
| `message` | 给人看的提示文案 |
---
仍可用手机号 API无凭票或试运行
```http
POST /api/v1/auth/bind/phone-lookup
Content-Type: application/json
@@ -163,7 +210,7 @@ Content-Type: application/json
{ "phone": "13531041944" }
```
响应要点:`exists``tenant_name``masked_name``need_confirm``message`**不**执行绑定)。
响应要点:`exists``tenant_name``masked_name``need_confirm``sms_required_unless_attested``message`**不**执行绑定)。
```http
POST /api/v1/auth/bind/phone-confirm
@@ -173,16 +220,25 @@ Content-Type: application/json
"phone": "13531041944",
"host_key": "< host_key>",
"confirm": true,
"local_database_id": " ID"
"local_database_id": " ID",
"attested_same_phone": true,
"sms_code": ""
}
```
| 字段 | 说明 |
|------|------|
| `attested_same_phone` | **试运行**可传;**正式且已启凭票**时禁用,须改用 ticket-exchange |
| `sms_code` | **试运行**可不传;正式异号必填 |
> **试运行**(当前):`SMS.RequireForBind=false` 或 `Provider=off` → 绑定不校验短信,仍须 `confirm=true`。正式:`RequireForBind: true` 且 Provider 非 off。
| 场景 | 行为 |
|------|------|
| 同号命中公司成员 | **必须询问**「已有账号是否绑定」;确认才 `phone-confirm` |
| 同号命中公司成员 | **必须询问**「已有账号是否绑定」;确认才 `phone-confirm` / 或凭票换票 |
| 用户取消 | 不绑定;可改走绑定码 / 换号 |
| 无此成员 | 提示用绑定码;**勿**用超管号 `13531041945` 测 |
| 生产联调样例 | 智建与宇恒均为 **`13531041944`** |
| 生产联调样例 | 智建与宇恒均为 **`13531041944`** → 凭票或弹确认 |
### 未绑定时客户端流程Z13d · 宇恒待接)
@@ -509,6 +565,8 @@ CREATE TABLE IF NOT EXISTS orders (
|------|------|------|
| POST | `/api/v1/auth/token` | 换票;响应可含 `channel_id`/`online_db_id`/`sync_bound`Z12a |
| GET | `/api/v1/agents/me` | 智能体自查落点Z12b |
| POST | `/api/v1/auth/yuheng/ticket-exchange` | 宇恒凭票免登录换票(仅宇恒 HMAC |
| GET | `/api/v1/auth/bind/policy` | 绑定策略:`require_for_bind` / `trial_mode` / `yuheng_ticket_enabled` |
| POST | `/api/v1/auth/bind-code/redeem` | 绑定码兑换公开Z13b |
| POST | `/api/v1/auth/bind/phone-lookup` | 同号探测不绑定Z13c |
| POST | `/api/v1/auth/bind/phone-confirm` | 同号确认后绑定Z13c-1 |