Poco 使用手册
平台说明

浏览器登录态设计

基于 Auth State 的浏览器登录态架构说明

1. 背景

旧版浏览器登录态主要依赖用户 base profile 复制到会话 profile。在以下场景下,容易出现“已登录后再次对话仍需重登”或“旧状态覆盖新状态”:

  • 浏览器实例在同一容器内被关闭并重新拉起,CDP 上下文变化。
  • 会话容器被回收后重建,profile 复制时机与浏览器写盘时机不一致。
  • 多运行实例并发读写 profile,存在文件级时序覆盖。
  • 用户在远程浏览器手动登录后,任务浏览器是否继承登录态依赖 profile 是否已经稳定落盘。

当前实现已废弃“用户 base profile 复制会话 profile”方案,将用户登录态提升为 Backend 管理的逻辑状态。

2. 目标与范围

2.1 目标

  • 以用户级 Auth State 作为唯一持久化真相源。
  • 废弃任务启动时的用户 base profile 复制机制。
  • 支持远程浏览器手动登录后,后续任务浏览器稳定复用登录态。
  • 支持任务浏览器登录后,后续远程浏览器也能恢复登录态。
  • 支持同容器浏览器重启后的自动恢复。
  • 支持多运行实例并发提交时的一致性合并。

2.2 范围

  • 当前稳定支持内置 Playwright MCP / CDP 浏览器链路。
  • agent_browser 已接入同一套 Auth State hook,但仍属于受限/实验链路;涉及登录态复用的任务优先使用 Playwright MCP。
  • 当前仅覆盖 Cookie + localStorage
  • 不新增独立容器服务。
  • 不引入站点白名单与多策略切换。
  • 不覆盖 IndexedDB、ServiceWorker、CacheStorage、sessionStorage、浏览器缓存、完整 Chrome profile。

3. 设计原则

  • 单一真相源:Backend Auth State 是唯一长期保存登录态的位置。
  • 低侵入:仅在远程浏览器边界、任务会话边界、浏览器工具调用边界插入逻辑。
  • 低耦合:Backend/Executor Manager/Executor 各自职责单一。
  • 明确语义:导出状态必须区分“未观测”与“显式删除”,避免误删。
  • 易扩展:后续可在同模型上扩展 IndexedDB、ServiceWorker、CacheStorage 等状态类型。

4. 总体架构

4.1 组件职责

  • Backend:加密存储用户级 Auth State,提供快照读取、版本提交、清空接口,执行并发合并。
  • Executor Manager:在远程浏览器和任务浏览器边界同步 Auth State,负责快照落盘与终态提交。
  • Executor:通过 CDP 注入/导出浏览器状态,在浏览器重启时自动再注入。

4.2 核心思路

  • 远程浏览器启动:拉取 Auth State 并注入浏览器。
  • 远程浏览器停止/删除/任务启动前:导出远程浏览器当前状态并提交 Backend。
  • 任务启动:拉取最新 Auth State 快照并写入会话工作区。
  • 任务运行:浏览器工具调用前后通过 CDP 做注入、导出和自愈。
  • 任务结束:导出最终状态并提交 Backend,按版本合并。

4.3 与旧 profile copy 的关系

  • 不再从用户 base profile 复制到会话 profile。
  • 任务容器使用容器内 /tmp/poco-task-browser-profile 作为临时浏览器 profile。
  • 远程浏览器使用容器内 /tmp/poco-remote-browser-profile 作为临时浏览器 profile。
  • 远程浏览器和任务浏览器之间的登录态传递只通过 Backend Auth State 完成。
  • 旧的历史 profile/cache 目录不再作为兼容路径参与读写,也不再作为登录态清理目标。

5. 数据模型(Backend)

新增表:user_auth_states

  • tenant_id (varchar, PK)
  • user_id (varchar, PK)
  • schema_version (int, not null)
  • version (bigint, not null)
  • cleared_at_version (bigint, not null)
  • encrypted_state (text/jsonb, not null)
  • updated_by_run_id (varchar, nullable)
  • updated_at (timestamp with time zone, not null)

说明:

  • encrypted_state 保存加密后的 Auth State,不裸存 Cookie/localStorage token。
  • 加密密钥通过 Backend 配置管理,不下发到 Executor 或 Executor Manager。
  • tenant_id + user_id 作为隔离边界,内部接口不得通过 query 参数任意指定其他用户。

解密后的 Auth State 结构:

{
  "cookies": [
    {
      "name": "sid",
      "value": "...",
      "domain": ".example.com",
      "path": "/",
      "expires": 1767225600,
      "httpOnly": true,
      "secure": true,
      "sameSite": "Lax"
    }
  ],
  "local_storage": {
    "https://example.com": {
      "token": "...",
      "user_id": "123"
    }
  },
  "observed_scopes": {
    "cookie_domains": [".example.com"],
    "local_storage_origins": ["https://example.com"]
  },
  "tombstones": {
    "cookies": [
      {
        "name": "sid",
        "domain": ".example.com",
        "path": "/"
      }
    ],
    "local_storage": [
      {
        "origin": "https://example.com",
        "key": "token"
      }
    ]
  }
}

6. 内部接口(Backend)

所有接口必须使用内部鉴权:

  • X-Internal-Token
  • X-User-Id
  • X-Tenant-Id(若当前系统已有统一 tenant 来源,可复用现有上下文)

6.1 读取快照

GET /api/v1/internal/auth-state/snapshot

返回:

{
  "tenant_id": "default",
  "user_id": "u1",
  "version": 12,
  "schema_version": 1,
  "state": {
    "cookies": [],
    "local_storage": {},
    "observed_scopes": {
      "cookie_domains": [],
      "local_storage_origins": []
    },
    "tombstones": {
      "cookies": [],
      "local_storage": []
    }
  }
}

6.2 提交状态

POST /api/v1/internal/auth-state/commit

请求:

{
  "base_version": 12,
  "base_state": {},
  "new_state": {},
  "run_id": "run_123"
}

返回:

{
  "tenant_id": "default",
  "user_id": "u1",
  "version": 13,
  "schema_version": 1,
  "state": {}
}

6.3 清空状态

DELETE /api/v1/internal/auth-state

用于“清空远程浏览器数据”时同步清空 Auth State。

7. 关键时序

7.1 远程浏览器启动

  1. Backend remote-browser/start 代理到 Executor Manager。
  2. Executor Manager 启动或复用用户远程浏览器容器。
  3. Executor Manager 调 Backend snapshot 获取最新 Auth State。
  4. Executor Manager 通过远程浏览器 CDP 注入 Cookie + localStorage
  5. 远程浏览器容器继续作为用户交互入口运行。

7.2 远程浏览器停止

  1. Executor Manager 先通过 CDP 导出远程浏览器当前状态。
  2. 调 Backend commit(base_version, base_state, new_state)
  3. 停止 Chrome,停止远程浏览器容器。
  4. 远程浏览器 profile 可保留为运行缓存,但不能作为长期真相源。

7.3 远程浏览器数据删除

  1. Executor Manager 停止远程浏览器容器。
  2. 调 Backend DELETE /api/v1/internal/auth-state 清空 Auth State。
  3. 清理远程浏览器本地 baseline 文件,避免后续 flush 继续基于旧基线生成删除语义。
  4. 不再清理历史 profile/cache 目录;这些目录不是当前登录态真相源。

7.4 任务启动

  1. Executor Manager 判断 browser_enabled=true
  2. 若用户远程浏览器容器正在运行,先导出并提交一次远程浏览器状态。
  3. 调 Backend snapshot 获取 {version, state}
  4. 将快照写入会话工作区:/workspace/.poco/auth-state/base.json
  5. 创建任务容器,使用容器内临时 Chrome Profile,不执行用户 base profile copy。
  6. Executor 启动后等待 CDP ready,并注入 base.json
  7. 初始化 working_state

7.5 任务运行(浏览器重启自愈)

  1. 浏览器工具调用前,Executor 检查当前浏览器实例指纹,例如 CDP version、webSocketDebuggerUrl、target id 组合。
  2. 若浏览器实例变化,立即使用 working_state 执行再注入。
  3. 浏览器工具调用后,导出当前 Cookie + localStorage,刷新 working_state
  4. 导出失败只记录错误,不生成删除语义。

7.6 任务结束

  1. Executor teardown 阶段导出最终状态。
  2. Executor 将最终状态写入:/workspace/.poco/auth-state/final.json
  3. Executor Manager 收到 terminal callback 后读取 base.jsonfinal.json
  4. 调 Backend commit(base_version, base_state, new_state)
  5. Backend 合并并返回最新版本。
  6. Executor Manager 清理 .poco/auth-state 工作文件。
  7. Ephemeral 任务容器按现有逻辑停止,profile 不再参与持久化。

8. 并发一致性(合并规则)

采用三方合并:base_statecurrent_state(库内最新)、new_state(本次提交)。

  • Cookie 主键:(name, domain, path)
  • localStorage 主键:(origin, key)

规则:

  1. new 相对 base 未变:保留 current
  2. new 相对 base 有变:应用 new
  3. 删除必须来自 tombstones,不能用“缺失”推断删除。
  4. 只有在 observed_scopes 内的 Cookie domain 或 localStorage origin 才允许产生 tombstone。
  5. 未观测到的 domain/origin/key 不参与删除。
  6. 合并完成后 version = version + 1

该策略避免旧运行实例整包覆盖新运行实例状态,也避免因导出范围不足误删其他站点登录态。

9. CDP 注入与导出规则

  • 注入:使用 CDP Network.setCookies
  • 导出:使用 CDP Network.getAllCookies
  • 过滤已过期 Cookie。
  • 保留 httpOnlysecuresameSiteexpires 等字段。
  • 注入 session cookie 时不传 expires <= 0,避免 CDP 将整批 cookie 判为非法。

9.2 localStorage

  • 注入:按 origin 打开或复用页面上下文后执行 localStorage.setItem
  • 导出:复用当前页面 target;必要时新开 origin target,并等待 location.origin 匹配后读取。
  • 导出范围只包含本次运行已访问或已注入的 origin。
  • 若 origin 页面无法打开或脚本执行失败,不生成 tombstone。

9.3 浏览器实现边界

  • 内置 Playwright MCP 是当前推荐且稳定的浏览器登录态链路。
  • agent_browser 通过 Bash 命令识别接入 Auth State hook,但受命令生命周期影响较大,例如同一条 Bash 中执行 agent-browser close 可能导致导出时页面已关闭。因此登录态复用场景暂不推荐依赖该链路。
  • 手动启动独立浏览器、独立 profile、独立 agent-browser session/config/state 文件都不属于统一 Auth State 范围。

10. 改造点(文件级)

10.1 Backend

新增:

  • backend/app/models/user_auth_state.py
  • backend/app/repositories/user_auth_state_repository.py
  • backend/app/services/auth_state_service.py
  • backend/app/schemas/auth_state.py
  • backend/app/api/v1/internal/auth_state.py
  • Alembic migration

调整:

  • backend/app/api/v1/remote_browser.py
  • 删除浏览器数据时同步清空 Auth State。
  • 启动/停止远程浏览器时保持 Auth State 同步语义清晰。
  • backend/app/core/settings.py
  • 增加 Auth State 加密相关配置。
  • .env.example
  • 增加用户需要配置的加密配置。
  • docs/zh/configuration.md
  • docs/en/configuration.md
  • 如影响 Docker 部署,再同步:
  • docs/zh/docker-compose.md
  • docs/en/docker-compose.md

10.2 Executor Manager

新增:

  • executor_manager/app/services/auth_state_stager.py
  • 拉取 Backend 快照并写入 /workspace/.poco/auth-state/base.json
  • executor_manager/app/services/auth_state_sync_service.py
  • 任务结束后读取 final.json 并提交 Backend。
  • executor_manager/app/services/browser_auth_state_sync_service.py
  • 远程浏览器 CDP 导出/注入。
  • 维护远程浏览器可信 baseline。

调整:

  • executor_manager/app/services/backend_client.py
  • 新增 snapshot/commit/clear 调用。
  • executor_manager/app/services/run_pull_service.py
  • 任务启动前调用 AuthStateStager
  • executor_manager/app/scheduler/task_dispatcher.py
  • legacy dispatch 路径同样调用 AuthStateStager
  • executor_manager/app/services/callback_service.py
  • terminal callback 后提交 final.json
  • executor_manager/app/services/container_pool.py
  • 移除任务启动时的 base profile copy。
  • 保留临时会话 profile 目录创建。
  • 保护 Chrome/agent-browser profile/session/config/state 相关环境变量,避免用户配置绕过统一 Auth State。
  • executor_manager/app/services/browser_sandbox_manager.py
  • 远程浏览器启动后注入 Auth State。
  • 远程浏览器停止前导出并提交 Auth State。
  • 删除数据时清空 Backend Auth State。
  • executor_manager/app/services/browser_profile_manager.py
  • 已移除 ensure_session_profile_seeded 任务启动调用。
  • executor_manager/app/schemas/task.py
  • 已移除 browser_profile_copy_mode

10.3 Executor

新增:

  • executor/app/services/auth_state_bridge.py
  • CDP 注入与导出。
  • 浏览器实例指纹检测。
  • base.jsonworking.jsonfinal.json 读写。
  • executor/app/hooks/auth_state.py
  • 在 setup 注入状态。
  • 在 browser tool 调用前后做自愈与导出。
  • 识别 Playwright MCP 工具事件与 agent-browser Bash 命令。
  • 在 teardown 写入 final state。

调整:

  • executor/app/api/v1/task.py
  • browser_enabled=true 且浏览器实现支持 Auth State 时注册 AuthState hook。
  • executor/app/core/engine.py
  • Playwright MCP 通过 CDP 连接任务容器内 Chrome。
  • agent_browser 模式注入内置 agent-browser skill,并避免重复注入 Playwright MCP。
  • executor/app/schemas/request.py
  • 已移除 browser_profile_copy_mode 相关输入。

11. 实施步骤

  1. Backend:模型、迁移、加密存储、内部 API 与三方合并逻辑。
  2. Executor:AuthStateBridge、setup 注入、浏览器工具调用边界导出、teardown 写 final。
  3. Executor Manager:AuthStateStager、远程浏览器同步、任务启动快照、任务结束提交。
  4. 移除 profile copy:删除任务启动时的 ensure_session_profile_seeded 调用。
  5. 配置与文档同步:更新 .env.example 与中英文配置文档。
  6. 联调验证:远程浏览器登录、任务复用、任务登录、远程浏览器复用、并发提交。

On this page