Skip to content

Personal Data Hub — Phase 10.3 AIChat WebView 鉴权向导设计

版本: v0.1 (2026-05-21) | 状态: 设计稿 | 父文档: Personal_Data_Hub_Architecture.md · Adapter_AIChat_History.md

Phase 10.3 把 9 家国产 AI(DeepSeek / Kimi / 通义 / 智谱 / 混元 / 千帆 / 扣子 / Dreamina / 豆包)的 Cookie 鉴权流程做成统一向导:用户在 ChainlessChain UI 内打开厂商登录页,登录成功后自动抓 cookie,注册到 AIChatHistoryAdapter桌面 Electron 主进程承载实际 BrowserView + session.cookies.getcc ui web-shell 因浏览器同源策略无法越权读厂商 cookie,走"用户复制 cookie 字符串"备用路径(详 §6)。

本文件单独成稿是因为:父文档 Adapter_AIChat_History.md §11 只给一行 "WebView 鉴权流程",§7 给 G2/G8 验收目标,§12 给 T5/T7 缓解,没有具体到 Electron API / IPC 协议 / Vue 组件 / 9 vendor cookie matrix / re-login UX。本文件填这部分空白。

0. 设计动机

AIChatHistoryAdapter 在 Phase 10.2 已落地全部 9 家 vendor sub-adapter(SPEC.validateCookie / listConversations / listMessages 三接口齐全),但至今没有一个用户能在 UI 里点的"添加 AIChat 来源"流程。当前唯一注册方式是:用户自己用浏览器开发者工具复制 cookie → 拼成 JSON → 走 register-aichat-vendor IPC。这显然不可用化产品落地。

Phase 10.3 把这个 gap 填上:

角色现状Phase 10.3 目标
普通用户不可能注册成功桌面/Web 弹窗式向导,3 步走完一家
开发者cookie 必须手抠UI 自动抓 cookie,写文档时仅维护 vendor matrix
QA无 smoke 路径每家 vendor 走通后 fixture 化,回归全自动

1. 目标 / 非目标

目标 (G1-G8)

  • G1 — Wizard 完成一家全流程时间 ≤ 90 秒(含用户登录时间)
  • G2 — 桌面 Electron 端用 BrowserView + session.cookies.get 抓 cookie,零手工拷贝
  • G3cc ui web-shell 端走 fallback 路径(用户在外部浏览器登录 → 在 UI 粘贴 cookie 字符串 → 服务端校验)
  • G4 — 9 家 vendor 统一向导:vendor picker → modal browser → cookie probe → validateCookie → register
  • G5 — Cookie 过期 health-check 每 6 小时跑一次;过期 vendor 在 UI 红点 + 一键重登
  • G6 — 用户在任意一步取消都不残留状态(不写 vault / 不写 aichat-accounts.json)
  • G7 — 全程审计日志(audit_log 表 action=register-aichat-* + 时间 + vendor + 来源 IP=local
  • G8 — vendor 失败不阻塞其他 vendor(单家 cookie 抓失败 → wizard 标红 → 用户可跳过 / 重试 / 改走 fallback)

非目标

  • 做 OAuth2 / API token 鉴权 — 9 家厂商目前不开放个人 API key 给 web chat 历史,v1 全走 cookie。
  • 自动化登录 — 用户必须自己输用户名密码 + 短信验证码(避免反爬 / ToS 风险)。
  • 同步登录态到云端 — cookie 永远只落本地 aichat-accounts.json (0600)。
  • 反风控 — adapter 默认节奏温和,触发风控就停(per T3)。

2. 顶层架构

┌────────────────────────────────────────────────────────────────────┐
│ 渲染进程 (Vue3 / Electron + web-panel SPA)                          │
│   AIChatWizard.vue                                                  │
│   - Step 1: vendor 选择 (9 卡片,已注册 vendor 标 ✓)               │
│   - Step 2: 内嵌 BrowserView (electron) / 外链 + 粘贴框 (web-shell) │
│   - Step 3: 抓 cookie → validateCookie → 提示成功 + close           │
└──────────────────────┬─────────────────────────────────────────────┘
                       ↓ IPC: personal-data-hub:aichat-* (4 个新通道)
                       ↓ WS:  personal-data-hub.aichat-* (镜像)
┌────────────────────────────────────────────────────────────────────┐
│ 主进程 / cc ui 服务端                                                │
│   aichat-wizard-controller.js                                       │
│   - openVendorLogin(vendor)  → 创建独立 partition + BrowserView     │
│   - probeCookies(vendor)     → session.cookies.get(domain matrix)   │
│   - registerVendor(vendor, cookies) → AIChatHistoryAdapter 注册     │
│   - rotateLoginPartition(vendor) → 清旧 cookie 重开                 │
└──────────────────────┬─────────────────────────────────────────────┘

┌────────────────────────────────────────────────────────────────────┐
│ Hub 现有能力                                                         │
│   - AIChatHistoryAdapter (Phase 10.1)                              │
│   - aichat-accounts.json 持久化                                     │
│   - HealthCheck 调度(新增:每 6h 跑 validateCookie 巡检)           │
└────────────────────────────────────────────────────────────────────┘

两端差异

桌面 Electroncc ui Web-Shell
浏览器载体BrowserView (主进程拥有)外部浏览器 (用户自己)
Cookie 提取session.fromPartition(...).cookies.get({url})用户复制粘贴(开发者工具 / EditThisCookie)
同账号续登走 partition,浏览器记住登录用户自己在外部浏览器记住
体验等级A 级(一键)C 级(手工但可控)

Web-shell 没法 A 级 — 浏览器同源策略 + 第三方 cookie 隔离让 cc ui 起的服务端永远读不到 chat.deepseek.com 的 cookie。承认这一点比硬上来强。

packages/personal-data-hub/lib/adapters/ai-chat-history/cookie-capture-spec.js 实现,与 vendors/*.js 的 SPEC 解耦(adapter 层保持纯 HTTP)。每条 entry:

字段类型说明
vendorstringdeepseek / kimi / tongyi / zhipu / hunyuan / qianfan / coze / dreamina / doubao
loginUrlstringwizard 打开的首页 URL(与 SPEC.loginUrl 一致)
cookieDomainsstring[]session.cookies.get 查询用的 domain 列表
requiredCookiesstring[]至少存在 1 个就视为登录成功(验证步先这层 + validateCookie 再确认)
postLoginPathHintsstring[]URL path 含其一时强提示"登录已成功"(如 /chat/c/
cookieMaxAgeHintDaysnumber经验值,过此值 UI 提前 3 天预警
notesstringwizard 内显示的用户提示(用户名 vs 邮箱 vs 手机 / 是否需短信)

Matrix(v0.1 用户社区可贡献 patch):

vendorloginUrlrequiredCookies (至少 1)maxAgeHintDays
deepseekhttps://chat.deepseek.com/userToken, intercom-session-*30
kimihttps://kimi.moonshot.cn/access_token, refresh_token30
tongyihttps://tongyi.aliyun.com/XSRF-TOKEN, login_aliyunid7
zhipuhttps://chatglm.cn/chatglm_token, cgsessionid30
hunyuanhttps://yuanbao.tencent.com/hy_token, hy_user, uin14
qianfanhttps://yiyan.baidu.com/BDUSS, BAIDUID, STOKEN7
cozehttps://www.coze.cn/sessionid, passport_csrf_token, s_v_web_id14
dreaminahttps://jimeng.jianying.com/sessionid, passport_csrf_token14
doubaohttps://www.doubao.com/chat/sessionid, sid_guard14

字段名是反向工程结果,会变。Phase 10.4 fixture pin 时把每家真实 cookie 截屏入 __fixtures__/aichat-cookies/<vendor>.txt 锁住一版;adapter manifest 加 cookieSpecVersion 字段,未来不兼容变更 bump。

4. IPC / WS 接口(新增 4 通道)

桌面 IPC + cc ui WS 双登记,命名遵循既有约定(colon vs dot):

通道入参出参双端可用
aichat-open-login{ vendor, opts?: { reuseSession?: boolean } }{ ok, sessionId, helpText, fallbackMode? } — Electron 启 BrowserView 返回 sessionId;web-shell 返回 fallbackMode: "paste" + helpText桌面 A 级 / web-shell C 级
aichat-probe-cookies{ vendor, sessionId? } (web-shell 传 { vendor, cookieHeader }){ ok, cookies: Record<string, string>, foundRequired: string[], missing: string[] }双端
aichat-register-vendor{ vendor, cookies }{ ok, accountId, validation: { ok, userId?, reason? } } — 内部串联 validateCookie + 持久化双端
aichat-rotate-login{ vendor }{ ok, sessionId } — 清旧 partition cookie + 重开 BrowserView(web-shell 仅返回 helpText)桌面 A 级 / web-shell C 级

已有但相关aichat-list-accounts / aichat-unregister-vendor / aichat-validate-cookie — Phase 10.2 已通过 register-aichat/unregister-aichat/list-aichat-accounts 暴露,本 Phase 沿用。

4.1 流式细节

aichat-open-login 在 Electron 端会推 2 个事件到 aichat-login-progress.<sessionId> 通道(与既有 sync-adapter-stream 同模式):

event.kindpayload说明
nav{ url, title }每次 BrowserView did-navigate 推一次(UI 实时显地址栏)
login-detected{ vendor, requiredFound: string[] }postLoginPathHints 命中 OR requiredCookies 至少 1 个出现 → 主动提示用户"可以关窗了"

5. UI 流(Vue 组件 AIChatWizard.vue

3 步走,全部嵌入 PersonalDataHub.vue 现有"配置抽屉"右侧 tab(与 Email / Alipay 同 widget 容器):

Step 1 — Vendor Picker

  • 3×3 卡片网格(每家 logo + displayName + 状态)
  • 状态标:未连接 / ✓ 已连接(YYYY-MM-DD) / ⚠ Cookie 即将过期(还剩 3 天) / 🔴 失败
  • 点击 + 跳 Step 2;点击已连接卡片显 dropdown(同步 / 重登 / 注销)

Step 2 — 鉴权

桌面 Electron 分支

[address bar (read-only, 主进程推 nav event)]
┌─────────────────────────────────────────┐
│  BrowserView 嵌入 (640 × 800)           │
│  - 用户在这里登录                       │
│  - 主进程监听 cookie 出现               │
└─────────────────────────────────────────┘
[提示横幅: "登录后自动检测,可关闭窗口"]
[取消] [手动检测] [我已登录,继续]

Web-Shell 分支

[外链按钮: "在浏览器打开 https://chat.deepseek.com/ →"]
[多行文本框: 粘贴 Cookie 字符串]
[助手: 如何获取 cookie?(展开 EditThisCookie / DevTools 指南)]
[取消] [验证]

Step 3 — 校验 + 注册

  • aichat-probe-cookies(桌面)或解析粘贴串(web-shell)
  • 显示 foundRequired / missing,缺关键 cookie 红字
  • aichat-register-vendor 内部串 validateCookie → ok 写 aichat-accounts.json → audit
  • 成功 → Confetti + 跳回 Step 1,对应卡片变绿
  • 失败 → 显示 reasonUNEXPECTED_RESPONSE_SHAPE / 网络 / cookie 不全) + 三按钮:重试 probe / 重新登录 / 转 fallback 粘贴

后台 AIChatHealthChecker 每 6h 跑一遍(首次启动 30s 后跑 1 次):

forEach registered vendor:
  result = vendor.SPEC.validateCookie({ httpClient: clientFor(vendor), session })
  if (!result.ok):
    mark accounts.json entry { lastHealth: { ok:false, reason, at } }
    push notification → PersonalDataHub.vue 卡片红点

UI 卡片点 🔴 重登

  • 桌面:调 aichat-rotate-login → 主进程清 partition 该 vendor 全部 cookie → 重启 BrowserView → 走 Step 2/3
  • Web-shell:弹粘贴框 → Step 3

7. 持久化

%APPDATA%\chainlesschain-desktop-vue\.chainlesschain\hub\aichat-accounts.json(已有,0600,本 Phase 仅扩字段):

json
{
  "deepseek": {
    "vendor": "deepseek",
    "registeredAt": 1747800000000,
    "cookies": { "userToken": "...", "intercom-session-xxx": "..." },
    "userId": "u_123",
    "displayName": "DeepSeek",
    "lastSyncAt": 1747900000000,
    "lastHealth": { "ok": true, "at": 1747900000000 },
    "cookieSpecVersion": 1
  }
}

cookieSpecVersion 字段:每次 cookie-capture-spec.js 不兼容变更 bump,旧 entry 升级前 health-check 主动 mark ok:false, reason:"SPEC_VERSION_DOWNGRADE"

8. 测试矩阵

测试数量
单元 — cookie-capture-spec9 家 spec 形状 / loginUrl host == cookieDomains 主域 / requiredCookies 非空 / 不存在重复 vendor8 测
单元 — wizard-controlleropen / probe / register / rotate 4 happy + 4 error path + 1 vendor unknown9 测
集成 — IPC roundtrip4 新通道在 desktop-app-vue + cc ui WS 端到端8 测(4×2 shell)
Vue 组件 — AIChatWizardStep 1 卡片状态 / Step 2 两分支 / Step 3 成功失败6 测
真账号 smoke每 vendor 一次 Wizard 真走通 + 1 次 health-check 过期模拟9+1

cookie-capture-spec.test.js 在本 Phase 同步落地(与本 design 一起 commit);其余测试随 wizard impl 推进。

9. Phase 拆分(工期估算)

Sub-phase内容工期
10.3.1cookie-capture-spec + 单测(本 Phase 同步落地0.3d
10.3.2wizard-controller 主进程 + 4 IPC + 单测0.7d
10.3.3AIChatWizard.vue + 集成进 PersonalDataHub.vue1d
10.3.4cc ui WS 镜像 + 粘贴 fallback UI0.5d
10.3.5HealthChecker + 红点 UI + 重登流0.5d
10.3.69 vendor 真账号 smoke + fixture pin1d
~4d

跟父文档 Adapter_AIChat_History.md §11 / Personal_Data_Hub_Architecture.md Phase 10 路线图工期一致。

10. Traps & 风险(10 个)

#Trap描述缓解
T1BrowserView partition 缓存污染一个 vendor 留下的 cookie 影响另一个 vendor 登录每 vendor 独立 partition persist:aichat-<vendor>;rotate 时 session.clearStorageData
T2部分 vendor 用 HTTP-only cookieDevTools 看得到但 session.cookies.get 拿不到Electron session.cookies.get 默认能取 HTTP-only(与 chromium DevTools 同权限);Web-shell fallback 粘贴用户得开 Application 面板而非 document.cookie
T3反风控识别 BrowserView UA厂商把 Electron UA 识为 bot 拒登主进程在 webContents 设 chrome stable UA:session.setUserAgent(navigator.userAgent.replace(/Electron\\/[\\d.]+ /, ""))
T4postLoginPathHints 误判用户登录前先访问 /chat 公开页 → 误推 login-detectedpostLoginPathHints + requiredCookies 至少 1 个同时满足才推;用户也可手动按"我已登录"
T5用户在 wizard 外开同名 vendor 登录系统浏览器的 cookie ChainlessChain 看不到UI 引导走 fallback 粘贴;不静默失败
T6Cookie 截短粘贴用户从浏览器复制时遗漏部分 cookie解析时校验 requiredCookies 全有;缺则报"已识别 X / Y 关键 cookie"
T7厂商 cookie 名变更spec 写的 userToken 改名 user_token_v2adapter manifest cookieSpecVersion + health check 报 SPEC_VERSION_MISMATCH + 用户社区 PR 流程
T8wizard 中途崩溃残留 partitionBrowserView crash / 用户强关进程 → partition cookie 留下启动时 aichat-wizard-controller.cleanupOrphanPartitions() 扫所有 persist:aichat-* 不在 accounts.json 的 partition + 清除
T9web-shell 粘贴的 cookie 含分号空格混乱用户复制不规范解析时容忍 ; / ; / 多空格 + trim 每对 key=value
T10已注册 vendor 重新走 wizard 覆盖 cookie用户重复点 + 也许卡在登录页Step 1 卡片改 "重新登录" 按钮(不是 +);明确文案;不动 registeredAt,只更 cookies + lastHealth

11. 跨端等价

接口桌面 Electroncc ui WSAndroidiOS
aichat-open-loginA 级 BrowserViewC 级 fallback 粘贴RPC 转桌面 BrowserView (Phase 14 远程操控)同 Android
aichat-probe-cookies主进程读 session服务端解析粘贴RPCRPC
aichat-register-vendor全等价全等价RPCRPC
aichat-rotate-loginA 级C 级RPCRPC

移动端永远不复刻 BrowserView — 通过 P2P 远程操控(per Phase 14 设计稿)转给桌面:

iPhone → P2P DC RPC "aichat.openLogin" → 桌面 mobile-bridge
  → 主进程开 BrowserView (桌面显示 / iPhone 仅看 nav 事件流)
  → 登录完成 cookies 落桌面 vault → iPhone 收 ok 返回

移动端 Phase 14 需新增 personal-data-hub.aichat.* 5 个 RPC 子项到 SeedRegistry(接 Phase 14.1 节奏,对 ~0.5d 数据层 + 0.5d UI)。

12. 演进路线

v1(本设计)

  • 9 家国产 AI 全 Wizard 化
  • 桌面 A 级 / web-shell C 级 / 移动端经由 Phase 14 远程

v2

  • 海外厂商(ChatGPT / Claude / Gemini / Perplexity)扩 spec — 海外 cookie 鉴权门槛更高,需配合 OAuth2 时切轨
  • 厂商 API token 鉴权(用户提供自己 API key),跳过 Wizard 全程
  • Wizard 录屏录像选项(用户主动开启用于贡献社区 fixture)

v3

  • AI 厂商社区贡献 spec marketplace(spec 文件 + fixture + 测试用例)
  • 自动检测 cookie spec 升级 + diff 推 PR

13. 参考

ChainlessChain 系统设计文档 — 面向开发者