Agent 调用企业 API 还在用明文 Token?货拉拉这套 CLI/SSO 鉴权方案值得抄

Agent 调用企业 API 还在用明文 Token?货拉拉这套 CLI/SSO 鉴权方案值得抄

你的 Agent 还在裸奔调 API?这篇文章可能会改变你的做法。

2026 年 3 月底,飞书开源了飞书 CLI,一个多月拿了 1 万+ star。这个项目的意义不只是"把飞书功能搬到命令行"——它第一次系统性地展示了企业系统如何以「Agent 友好」的方式开放能力。文档、审批、日历、消息,全变成可组合的命令,大模型直接当函数调用。

但当你真想把企业内部的业务 CLI 接入 Claude Code、OpenClaw 这些 Agent 框架时,第一个撞上的墙不是接口不够用,而是——鉴权

货拉拉技术团队最近公开了他们的解法:一套面向 Agent Skill 的 CLI/SSO 鉴权体系。核心卖点三个:Token 不落盘不暴露、多用户隔离、飞书一键授权无感知。我读完了他们的技术方案,觉得这套架构的设计思路值得每个在做 Agent 集成的人认真看看。

本文提纲

  1. 传统 API Key 为什么在 Agent 场景下翻车
  2. 四层架构:sso-cli、业务 CLI、sso-sdk、SSO 平台
  3. 安全存储:Keychain 主密钥 + 加密文件
  4. 多用户隔离:加密环境变量 + 文件锁
  5. 飞书 Hook 登录:从"生硬"到"无感"
  6. SSO 平台迭代:Poll 授权模式
  7. 业务 CLI 集成:最后一公里的安全闭环
  8. 与传统方案对比:差距在哪

传统 API Key 为什么在 Agent 场景下翻车

在 Web 时代,SSO 鉴权天然是"人在浏览器前"的模式:跳转到 SSO 平台 → 用户手动登录 → 回调拿 Token → 后续请求带着 Token。整个流程依赖人类的交互能力。

Agent 不行。Agent 没有浏览器,不会点按钮,无法完成交互式登录。

早期实践中最常见的做法是"预置 Token":开发者手动完成 SSO 登录,把长期 Token 写进环境变量、配置文件、甚至硬编码到代码里。这在个人玩具项目里没问题,但在企业环境下是灾难:

问题一:Token 大面积暴露。Token 以明文形式存在于 .envconfig.yaml、shell history、/proc/*/environ 等任何你能想到的地方。任何能读取文件系统的攻击者都能拿到。

问题二:多人共享沙箱身份混乱。一个团队的 Agent 沙箱里,产品同事 A 登录后存了 A 的 Token,研发同事 B 紧接着调用——没有用户隔离的话,B 的请求用的是 A 的身份。审计日志显示是 A 在操作,但实际是 B。权限控制形同虚设。

问题三:无法追溯具体 Agent 行为。当 Agent 代替人做了某个操作,审计系统只知道"这个 Token 做了这件事",不知道是哪个用户、在什么对话上下文中、让哪个 Agent 执行的。出了问题,根本没法溯源。

这三个问题指向同一个结论:必须为 Agent 设计一套原生的、脱离浏览器依赖的、多人隔离且防泄露的 SSO 鉴权体系

四层架构:sso-cli、业务 CLI、sso-sdk、SSO 平台

货拉拉的方案把鉴权拆成四个组件,各司其职:

MERMAID_BLOCK_0

sso-cli:独立的命令行工具,负责 SSO 登录编排、凭证安全存储、多用户隔离。不提供 Token 直接读取接口——你没法通过它拿到明文 Token。

业务 CLI:各业务团队开发的命令行工具(abtest-cli、trade-cli 等),Agent 实际调用的就是这些。它们不直接处理 Token,而是依赖 sso-sdk。

sso-sdk:内部私有包(Go),只有授权的模块才能引用。封装了从本地安全存储读取、解密 Token 的逻辑。

SSO 平台:公司统一单点登录服务,新增了 Agent 场景的 poll 授权模式——支持下发一次性 code,客户端轮询换 Token。

一次典型调用流:

  1. Agent 根据用户意图调用业务 CLI
  2. 业务 CLI 通过 sso-sdk 获取当前用户的 SSO Token
  3. Token 不存在或过期 → CLI 报错 → Agent 触发 sso-cli 登录
  4. sso-cli 向 SSO 平台申请一次性 code,通过飞书卡片让用户授权,后台轮询换 Token
  5. Token 加密写入本地,飞书卡片自动删除
  6. Agent 再次调用业务 CLI,正常返回结果

安全存储:Keychain 主密钥 + 加密文件

这是整套方案里我觉得最精巧的部分。

主密钥(Master Key) 存储在操作系统的原生密钥链中:
- macOS → Keychain
- Linux → Secret Service / gnome-keyring
- Windows → Credential Manager / DPAPI

主密钥不落在任何普通文件里,读取受操作系统用户权限保护。sso-cli 只在需要加解密时从 keychain 取出主密钥,用完立即从内存擦除。

Token 存储走的是"密文文件"路线:用户通过 SSO 登录拿到 Token 后,sso-cli 将 user → token 的映射序列化、用主密钥加密、写入本地文件。没有主密钥,拿到密文也解不开。

这个设计的核心假设是:沙箱环境可能被任何人读取文件系统,但攻击者通常无法直接访问运行中进程的操作系统密钥链(除非已经提权)。这就形成了两道防线:

攻击者拿到密文文件 → 没有主密钥 → 无法解密
攻击者拿到主密钥 → 需要操作系统 keychain 权限 → 需要提权
攻击者同时拿到两者 → 文件内多用户 key 粒度隔离 → 只能解密特定用户的 Token

对比传统方案把 Token 塞进 .env 文件或者 export TOKEN=xxx——差距不是一点半点。

多用户隔离:加密环境变量 + 文件锁

这是解决"多人共用沙箱"问题的关键设计。

每一轮 Agent 对话对应一个"当前用户"。Agent 框架启动子进程时,注入一组加密的临时环境变量来标识用户身份——不是明文用户名,而是经过对称加密的 salt。只有持有派生密钥的组件(sso-sdk)才能解密还原。

这组环境变量的安全属性:

  • 生命周期绑定对话:对话结束立即销毁
  • 不进 shell history:进程私有的环境块,不写入 /proc 的全局视图
  • 密文传输:即使被读取,看到的也是密文,无法知道当前用户是谁,更无法篡改为其他用户

并发控制通过文件锁保护:读操作并发(解密幂等),写操作加排他锁(避免登录写入竞态)。

这个设计的巧妙之处在于:它把"用户隔离"和"Token 隔离"合并在了一套机制里——同一个加密文件,通过 key 粒度区分不同用户,而不是每个用户一个文件。简化了并发控制,也减少了密文数量。

飞书 Hook 登录:从"生硬"到"无感"

安全做到位了,但初版的登录体验极其生硬:Agent 提示用户去浏览器登录 → 用户登录后回来说"好了" → Agent 触发轮询 → 拿到 Token 继续。

问题很明显:打断对话流,依赖用户主动告知,经常因为忘记触发轮询而超时。

Hook 模式彻底改变了这个体验:

  1. sso-cli 被调用时,拦截自身的 JSON 输出,生成一张飞书卡片消息
  2. 通过飞书 Bot 发送给当前用户,卡片含 SSO 登录链接,仅本人可见
  3. 用户点击卡片,浏览器完成 SSO 授权
  4. sso-cli 后台自动轮询 SSO 平台,用一次性 code 换 Token
  5. 拿到 Token 后:加密存储 → 通知飞书 Bot 删除卡片(不留聊天记录痕迹)→ 返回成功
  6. Agent 无缝继续执行业务 CLI

用户唯一要做的就是点一下飞书卡片。整个流程对用户来说几乎是透明的。

降级方案也考虑了:飞书卡片不可用时,退化为普通文本消息发登录链接。消息可能留在聊天记录里,但链接本身不包含 Token,风险可控。

SSO 平台迭代:Poll 授权模式

传统 SSO 只支持实时 Web 回调,无法适配 Agent 的异步场景。货拉拉推动了 SSO 平台的关键迭代——Agent Poll 授权模式

流程是这样的:

  1. sso-cli 向 SSO 平台请求一次性登录链接,平台同时返回绑定的短期 code
  2. 链接通过飞书卡片给用户
  3. 用户浏览器打开链接完成登录,链接立即失效
  4. sso-cli 间隔轮询 SSO 平台,用 code 换 Token
  5. 第一次成功换取后 code 标记已用,后续请求被拒绝

安全设计要点:

  • 一次性链接 + 一次性 code:防止链接被重复利用。即使泄露,一旦被正确使用即作废
  • code 定时失效:防止暴力轮询
  • 轮询幂等:第一次成功后,后续请求因 code 失效被拒绝,无副作用
  • 用户校验:授权用户和发起用户不一致时,sso-cli 拒绝并终止

这个 poll 模式的价值不只是服务于 Agent——它让 SSO 平台具备了支撑任何异步授权场景的通用能力。

业务 CLI 集成:最后一公里的安全闭环

业务 CLI 开发者不需要关心主密钥、加密文件、环境变量这些复杂细节。引入 sso-sdk,调用一个方法拿 Token,完事。

import "internal.example.com/sso-sdk"

func main() {
    token, err := sso_sdk.GetToken()
    if err != nil {
        // Token 不存在或过期,返回特定退出码
        // Agent 感知后触发 sso-cli 登录
        os.Exit(42)
    }
    // 用 token 调用业务 API
    callBusinessAPI(token)
}

sso-sdk 的权限控制是编译期的:包托管在内部 Go Module Proxy,仓库权限仅对授权模块开放。未经审查的业务 CLI 连 import 都做不到,编译直接失败。这比运行时控制更前置、更绝对。

存储与获取分离也是有意为之:sso-cli 负责登录(交互重、状态多、易出错),sso-sdk 负责读取(精简、可靠、无 IPC)。读取过程不经过网络,不经过进程间通信,纯本地解密,安全且快速。

逆向防护方面,团队也在考虑把 Token 获取逻辑编译为共享库(.so/.dylib)动态加载,或者用 CGO + 静态库内嵌并剥离符号,提升逆向分析成本。目前主要以私有包权限保证安全边界。

与传统方案对比:差距在哪

维度 传统 API Key / 预置 Token 货拉拉 CLI/SSO 方案
Token 存储 明文 .env / config / 环境变量 Keychain 主密钥 + 加密文件
Token 可见性 任何能读文件的人都能看到 常规途径完全不可见
用户隔离 无(共享同一 Token) 加密环境变量 + key 粒度隔离
审计追溯 只知道"这个 Token"做了什么 每次调用绑定真实用户身份
登录体验 手动登录后复制 Token 飞书卡片一键点击,无感知
Token 过期 手动刷新或等报错 自动检测 + 触发重新登录
权限控制 运行时检查 编译期仓库权限控制
泄露风险 高(多处明文暴露) 低(纵深防御,多层保护)

核心差距在安全模型上:传统方案假设"环境是可信的",货拉拉方案假设"环境是不可信的"——沙箱可能被任何人读取,Token 必须在任何常规载体中都不可见。这是一个根本性的思维转变。

你的 Agent 鉴权还在用 API Key 硬编码?评论区聊聊你踩过的坑。觉得有参考价值就点个赞,让更多人看到这套方案。


参考文档与链接

原始文章
- 货拉拉技术 - 面向 Agent Skill 的 CLI/SSO 鉴权体系 — 掘金原文,完整技术细节

相关项目与背景
- 飞书 CLI 开源项目 — 飞书 CLI 将文档、审批、日历等能力封装为 Agent 友好的命令
- Claude Code — Anthropic 的 Agent CLI 框架,Skill 机制是其核心扩展方式
- OpenClaw — 开源 Agent 框架,支持通过 Skill 调用外部 CLI 工具

安全技术参考
- OAuth 2.0 Device Authorization Grant — IETF RFC 8628,设备授权流程,Poll 模式的理论基础
- OWASP API Security Top 10 — API 安全风险清单,包含 Broken Authentication 等核心威胁
- macOS Keychain Services — Apple 官方密钥链文档
- Linux Secret Service API — Linux 密钥管理标准

Agent 安全相关
- Anthropic: Building effective agents — Agent 架构设计最佳实践
- GitHub: addyosmani/agent-skills — Agent Skill 设计模式和最佳实践集合


作者: itech001
来源: 公众号:AI人工智能时代
网站: https://www.theaiera.cn/
每日分享最前沿的AI新闻资讯和技术研究。

本文首发于 AI人工智能时代,转载请注明出处。

posted @ 2026-06-14 12:23  iTech  阅读(1)  评论(0)    收藏  举报