Univer Workspace如何保护AI代理登录安全:浏览器批准登录与OAuth PKCE认证原理解析
【免费下载链接】univer-workspaceAn open-source Office workspace where people and AI agents create, collaborate, and review together.项目地址: https://gitcode.com/gh_mirrors/un/univer-workspace
Univer Workspace 是一个开源的协作式 Office 工作区,让人类与 AI 代理(Agent)共同创建、编辑和评审文档。当 AI 代理需要登录用户的工作区时,登录安全就成了关键问题——它不能像网站那样依赖 Cookie,也不能把密码交给代理保管。Univer Workspace 采用「浏览器批准登录 + OAuth 授权码 + PKCE 认证」的组合方案,让敏感凭据始终留在用户浏览器和受保护的本地进程中,AI 代理拿到的只是短期、一次性的授权票据。本文将用尽量少的代码,讲清楚这套登录安全机制的工作原理。
为什么 AI 代理登录需要特殊的安全设计?
传统 Web 应用登录依赖浏览器 Cookie,而 Univer Workspace 的 AI 代理运行在本地 Harness 进程中(桌面客户端或 CLI),它有自己的"浏览器环境",直接复用用户浏览器的会话是不安全的。核心难题有三个:
- 公共客户端没有密钥:本地代理无法像服务端那样安全保存
client_secret,任何人都可以反编译它。 - 授权码会暴露在浏览器中:外部浏览器完成授权后,回调 URL 上的授权码可能被恶意页面截获。
- 需要用户明确同意:AI 代理代表用户操作,必须让用户在浏览器里亲眼确认"谁在请求、请求什么范围"。
Univer Workspace 的答案就是 OAuth 授权码流程加上 PKCE(Proof Key for Code Exchange)扩展,并配合本地回环端点与自定义协议做"最后一公里"的安全传递。
浏览器批准登录:一次完整登录流程拆解
整个登录流程在 apps/agent/src/oauth-authorization.ts 中实现,可以拆成 4 步:
1️⃣ 本地生成 state 与 code_verifier
本地代理调用beginOAuth时(见 oauth-authorization.ts),会用密码学安全随机数生成两样东西:
- state(32 字节随机值):防 CSRF 的"对暗号",回调时必须原样带回;
- code_verifier(48 字节随机值):PKCE 的"私钥",只保存在本地内存中,永不上网传输。
同时计算code_challenge = SHA256(code_verifier),随授权请求一起发出去。注意挑战值可以公开,但无法从挑战值反推出验证值——这正是 S256 方法的数学基础。
2️⃣ 打开外部浏览器完成身份认证
本地代理把用户重定向到工作区服务端的/api/auth/authorize端点。用户在自己的浏览器里正常登录,如果客户端配置了requiresConsent,还会看到一个授权同意页(consent page)。
这个同意页是登录安全的第一道人工防线:它清楚展示"哪个客户端(client_id)、以谁的身份、请求哪些权限范围(scope)",并提供 Allow / Deny 按钮。其实现见 oauth-authorization-router.ts,有几个值得注意的细节:
- 同意页携带一次性
consent_token,5 分钟过期、只能用一次、且绑定当前登录用户——重放攻击和跨用户伪造都会直接失败; - 用户选择 Deny 时,服务端回传
error=access_denied,代理侧不会创建任何会话; - 页面启用了严格的 CSP 头与
X-Frame-Options: DENY,防止被嵌入钓鱼页面。
3️⃣ 授权码的"安全回传":自定义协议而非直接落盘
工作区服务端验证身份后,签发一个60 秒有效、一次性使用的授权码(见 oauth-clients.ts),并重定向回本地代理的回调地址。
这里有个精巧设计:外部浏览器里没有桌面客户端的会话 Cookie(见 desktop-oauth.ts 中对 Origin/Cookie 围栏的说明)。因此回调页不直接完成登录,而是把code + state通过自定义协议univer-workspace://login#...交还给桌面应用(页面文案为"请打开应用以完成登录,你可以关闭此页面",见 desktop-oauth-page.ts)。
这样即使有人截获了浏览器中的授权码,攻击者也没有本地验证进程持有的code_verifier,无法完成令牌交换。
4️⃣ 本地 PKCE 交换,完成登录
桌面客户端收到授权码后,调用/auth/device/complete之类的本地端点(端点契约定义在 contract.ts),把code + state + code_verifier一起提交。服务端在 oauth-authorization-router.ts 的令牌端点中依次验证:
| 校验项 | 防的是什么 |
|---|---|
code_challenge与code_verifier的 S256 匹配 | 授权码被截获后的重放攻击 |
state与本地记录一致 | 跨站请求伪造(CSRF) |
redirect_uri精确匹配注册表 | 开放重定向攻击 |
| 授权码 60 秒过期 + 用后即删 | 长时重放 |
公共客户端禁止携带client_secret | 凭据混淆与误用 |
全部通过后,才签发会话令牌(sessionscope 才会返回access_token),代理进程通过 workspace-auth.ts 中的WorkspaceAuthService把身份与令牌绑定到本地进程——一个 Harness 进程只绑定一个远端身份,且切换身份时带有版本校验,防止登录过程中并发竞态。
没有密钥的客户端,PKCE 如何补上信任缺口?
PKCE 的本质是一句话:把"只有本地进程知道"的秘密,变成一次不可逆的数学承诺。
- 发起时:只公开
code_challenge = S256(code_verifier)(见 oauth-authorization.ts 中randomBytes(48)生成 verifier、createHash("sha256")生成 challenge 的过程); - 兑换时:服务端用
SHA256(收到的 verifier) === 存储的 challenge来证明"你就是发起请求的那个本地进程"。
由于 SHA-256 不可逆,公开 challenge 不会泄露 verifier;而没有 verifier,即使拿到授权码也换不到令牌。服务端验证逻辑见 validateOAuthCodeVerifier。
命令行(CLI)用户还有另一条路:设备授权流
如果 AI 代理以 CLI 形式运行(没有图形界面),Univer Workspace 还提供标准 OAuth 设备授权协议:本地进程请求一个短码user_code和验证 URL,用户在自己的浏览器打开该 URL 批准,CLI 则按固定间隔轮询交换结果,成功后才拿到workspace_session会话令牌。
整个流程见 device-authorization.ts,其中有两个安全细节值得称道:
- 验证 URL 必须与请求的 origin 完全同源,否则直接判定为跨域攻击并抛错(device-authorization.ts);
- 设备流程"不创建本地用户、Cookie 或浏览器会话",只做远端身份交换,职责边界清晰。
相关源码与模块路径速查
| 模块 | 说明 |
|---|---|
| apps/agent/src/oauth-authorization.ts | 本地代理侧 OAuth 发起与 PKCE 令牌交换 |
| apps/agent/src/desktop-oauth.ts | 桌面端登录端点与 Origin/Cookie 围栏 |
| apps/agent/src/desktop-oauth-page.ts | 外部浏览器回调页与自定义协议回传 |
| apps/agent/src/device-authorization.ts | 设备授权流(CLI 登录) |
| apps/agent/src/workspace-auth.ts | 本地进程级身份与令牌绑定服务 |
| apps/workspace/server/src/modules/identity/oauth-authorization-router.ts | 服务端授权端点、同意页与令牌端点 |
| apps/workspace/server/src/modules/identity/oauth-clients.ts | 客户端注册、PKCE 校验与一次性授权码签发 |
| apps/workspace/contracts/http/paths/auth.yaml | 认证相关 HTTP 接口的 OpenAPI 契约 |
总结:三层防线让 AI 代理登录"只可验证,不可窃取"
回顾整个设计,Univer Workspace 用三层防线回答了"AI 代理如何安全登录":
- 人工批准层:浏览器中的同意页 + 一次性 consent token,让用户对每次 AI 代理登录拥有知情权与否决权;
- 传输隔离层:授权码经自定义协议仅回传给本地应用,外部浏览器拿不到会话 Cookie,也拿不到令牌;
- 密码学验证层:OAuth PKCE(S256)确保只有持有
code_verifier的原始本地进程才能兑换令牌,配合 60 秒一次性授权码、redirect_uri 白名单与 CSP 等纵深防御。
对于希望在自己的产品中集成 AI 代理登录的开发者,这套"无密钥公共客户端 + 浏览器批准 + PKCE"的模式,是目前 OAuth 生态中最稳妥的参考实现之一,也值得直接参考 apps/agent/src/ 下的开源代码。
【免费下载链接】univer-workspaceAn open-source Office workspace where people and AI agents create, collaborate, and review together.项目地址: https://gitcode.com/gh_mirrors/un/univer-workspace
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考