# ADR-0012:业务系统账号绑定与凭据获取 - **状态**:已接受 - **日期**:2026-09-29 - **决策人**:技术负责人 - **相关**:任务表 A5.4 / A5.7;架构设计 4.1、4.3、6;实施设计 2.4、5;ADR-0004(桌面端授权)、ADR-0008(库归属) ## 背景 A4.1 已经落地「平台用户 → 各系统账号」的绑定表和策略(未绑定默认拒绝,一个系统停用不影响另一个),A4.3 也把凭据做成密文存储加一次性执行句柄。但有一件事当时刻意留空:**这条绑定里的登录态是怎么拿到的**。 A5 要接真实 APS,这个问题必须先答:如果答案错了,后面每个业务系统都要各写一套登录和续期逻辑,凭据会散落各处,「不同系统登录态互相独立」也守不住。 ## 选项 | 选项 | 做法 | 代价 | 不选的理由 | | --- | --- | --- | --- | | A 业务系统提供标准授权登录(OAuth2 / OIDC 授权码) | 平台发起跳转 → 用户在业务系统登录 → 回调带 code → 平台换 token | 需要业务系统支持标准协议;要处理回调与续期 | 选定为主 | | B 平台收账号密码,一次性换 token | 老系统没有标准登录时,平台弹窗收账号密码,调它的登录接口换 token,密码用完即弃 | 部分系统只能这么接;要明确「密码不落盘」的实现约束 | 作为过渡方案保留 | | C 长期 API Key / 服务账号 | 管理员在平台配置 key,挂在租户或实例上 | 没有按人的登录态,出问题查不到具体人 | 仅用于无人值守的系统级集成 | | D 平台存业务系统密码,每次调用现登 | 密码入库,调用前先登录 | 实现最直白 | 密码落盘等于把业务系统的身份长期托管给平台;失效判断、改密、审计全部变复杂 | ## 结论 选 A 为主、B 为过渡、C 限系统级。共同规则如下: | 项 | 结论 | | --- | --- | | 声明位置 | Provider manifest 增加 `auth` 声明(`oauth` / `password-exchange` / `apikey`),平台按声明走对应流程,平台侧接口不变 | | 平台职责 | 发起绑定、接收回调、兑换凭据、加密存储、续期、失效判定、日志脱敏;**不实现业务系统的登录页面** | | 存什么 | 只存 token / refresh token(或 API Key)的密文,**绝不存密码**;密码只在一次兑换调用里经过内存 | | 何时取用 | 只在一次 execution 内,经 A4.3 的一次性句柄;工具参数、事件、日志、模型上下文里都没有 | | 失效行为 | 该系统的调用立即被拒(`policy.identity_disabled` 或凭据不可用),界面提示重新绑定;其他系统不受影响 | | 解绑 | 删除绑定与密文;审计与执行历史保留(ADR-0008 的「执行历史不删」) | | 桌面端 | 走系统浏览器 + 本地 loopback 回调,不在内嵌 webview 里收集密码(与 ADR-0004 的授权码 + 设备绑定同一思路) | | 浏览器端 | 复用平台登录态发起绑定;业务系统 token 不下发给客户端(协议第 3 节) | ## 影响 - **对代码**:`server/provider-sdk` 增加 `auth` 声明与 `exchange()`;`server/core/identity` 增加绑定流程(发起 / 完成 / 解绑);`server/entry/http` 增加绑定端点;客户端设置页增加「账号绑定」区块 - **对任务**:A5.4 收敛为**实例路由**(哪个租户或工厂连哪个 APS 实例);新增 **A5.7 账号绑定与登录态** 承担本 ADR 的落地 - **对文档**:架构设计第 4.1、6 节补绑定机制;实施设计 2.4 与第 5 节补绑定步骤;协议第 4 节在实现时加端点,并遵循「四处同步」规则 - **不这么做的后果**:每个业务系统各自实现登录与续期,凭据散落在 Provider 内部,「凭据不出域」与「登录态互不影响」两条都会被绕过 ## 遗留 - APS 最终用哪种方式(它能不能提供标准授权登录):由 B5 的契约化接口层定,这一条不阻塞平台侧实现 - 一个用户在同一个系统里绑多个账号(多工厂账号):首版一人一系统一条绑定,等有真实需求再放开 - token 续期的失败重试与提醒策略:A5.7 落地时定