外观
Nexo — 2026-08-23 迭代需求文档
范围:把认证从 IM 中剥离为独立的生态级认证中心,并交付壳的第一个可安装桌面包。 验收标准见同目录 TC 文档,本文档只定义"做什么"与"为什么"。
1. 背景与目标
上一迭代(2026-08-16 单聊跑通)把 IM 地基跑通,但认证是长在 nexo-im-api 内部的:users / devices 表、登录接口、会话签发全在 IM 里。
Nexo 的形态不是一个 IM,而是一个壳 + 多子应用的工作台:IM 之后还有文档中心、会议、agent 应用。每个子应用都需要认证,而它们不应该各自实现一套,更不应该反向依赖 IM 拿用户资料。
本迭代的唯一目标:建立生态级认证中心 nexo-auth,让壳与 IM 都退化为它的 client;同时交付壳的第一个可安装桌面包。
为什么是现在做而不是以后做:认证中心要迁移 users / devices 两张表,当前只有 5 个种子账号、零真实业务数据,是整个项目生命周期里迁移成本最低的窗口。每推迟一周,成本都在涨。
2. 已知欠账(承接 2026-08-16 验收)
上一迭代 9 条验收通过 5 条,未通过 4 条。其中 1 条由本期认证中心顺带交付,其余 3 条明确排期,不在 2026-08-23 验收会上重复验证:
| 欠账项 | 处理 | 排期 | Owner |
|---|---|---|---|
| 「登录设备」列出多台设备(本机有标记);退出其中一台后该端 5s 内回登录页,另一台不受影响 | 本期交付(devices 迁入 nexo-auth,吊销通道为其天然载体) | 2026-08-23 | 待认领 |
| B 回复后 A 实时收到,双方看到的消息顺序完全一致 | 顺延 | 2026-08-30 | 待认领 |
| 同账号在第二台设备登录后两端都能正常收发,新消息两端都收得到 | 顺延 | 2026-08-30 | 待认领 |
| 客户端刷新/重启后历史消息完整、顺序不变,向上翻页可加载更早消息 | 顺延 | 2026-08-30 | 待认领 |
顺延的 3 条属于 IM 消息层问题(seq 设计、多端 fanout、分页),与本期认证改造无技术依赖,可并行推进但不占本期验收窗口。
3. 功能需求
P0
FR-1 认证中心 nexo-auth
- 新建独立仓库与独立服务,技术栈与现有后端一致(Hono + Drizzle + PostgreSQL)
- 拥有
users与devices两张表,从nexo-im-api全量迁走;nexo-im-api不再持有任何认证数据 - 实现 OAuth 2.1 最小子集:授权码模式 + PKCE、refresh token rotation、JWKS 公钥端点、托管登录页
- 不实现:OIDC discovery、userinfo 端点、多租户、第三方 IdP 联合登录、开放注册与密码找回(密码仍由管理员重置)
- 独立 database(与 IM 同一 PostgreSQL 实例但库级隔离),禁止跨库 join
FR-2 登录流程
nexo-auth托管唯一的登录页,任何子应用都不再自带登录表单- 子应用独立访问时(如直接打开 IM 地址):顶层窗口跳转认证中心 → 登录 → 回调带授权码 → 换取令牌
- 在壳内时:由壳完成登录流程,子应用不发生跳转(iframe 内第三方 cookie 已被浏览器禁用,跳转不可行)
- 已在认证中心登录的用户,打开第二个子应用不需要再次输入密码(SSO)
- 登录失败给出明确提示;回调地址必须在白名单内精确匹配,非白名单地址一律拒绝
FR-3 会话与设备模型
- 一台设备 = 一个会话 =
devices表中的一条记录。壳是设备的持有者,壳内的所有子应用共享壳的会话,不各自建立会话 - 「登录设备」列表展示本账号全部在线设备:设备名称与类型、登录时间、最近活跃时间,当前设备标注「本机」
- 可对任一设备执行「退出登录」(含本机):该设备凭证立即失效,≤ 5s 内其界面断开并回到登录页,提示「你的账号已在其他设备上退出登录」;其他设备不受影响
- 设备连续 30 天未活跃,凭证自动失效并从列表移除
FR-4 令牌模型与吊销
- 访问令牌为非对称签名 JWT(含设备标识),有效期 ≤ 15 分钟,资源服务本地验签,不回调认证中心
- 刷新令牌启用轮换,且服务端做复用检测:旧刷新令牌被重放时,吸销该设备整条会话
- 凭证存储分层:刷新令牌落盘(桌面端存所在平台的系统凭证库,Web 端存本地存储),访问令牌只驻留内存;子应用永不接触刷新令牌
- 设备被吊销时,认证中心主动通知资源服务;资源服务据此拒绝后续请求并主动断开该设备的长连接——这是"5s 生效"的实现载体,仅靠令牌过期无法满足该指标
- 登录持久化不得退化:刷新页面、重启客户端后仍处于登录态
FR-5 IM 接入改造
nexo-im-api降级为资源服务:拉取认证中心公钥本地验签,维护吊销集合,不再签发任何凭证- 「登录设备」页面改为读取认证中心数据
nexo-im-pc移除本地登录表单,改为走认证中心登录流程- 访问令牌到期时静默续期,用户无感知;续期失败才回到登录页
FR-6 壳接入与桌面包
- 壳成为认证中心的正式 client,登录后通过既有的 postMessage 桥接向子应用下发访问令牌,令牌临近过期时主动重发
- 前端 SDK 对子应用暴露统一接口(形如
getAccessToken()),内部自动判断运行在壳内还是独立访问并分流——子应用代码对两条路径无感知 - 交付可安装的 macOS 与 Windows 桌面包(Tauri),两个平台均能加载壳、完成登录、重启后保持登录态
- 桌面包由 CI 构建矩阵产出,两平台产物可下载安装;本期不做代码签名,Windows 上的 SmartScreen 警告属预期行为,不算缺陷
- 桌面端登录走本地回环回调(RFC 8252),用系统浏览器打开登录页,密码不经过应用本体
- 刷新令牌存入各平台的系统级凭证库(macOS 钥匙串 / Windows 凭据管理器),不落明文文件
随主线交付(不单独排期,但同样是本期交付物)
以下两条不是"资源不足可砍"的备选项——它们是主线工作的自然产物,做主线就会顺手做出来,但必须写明标准,否则会被做成半成品。
FR-7 统一日志
- 两个后端(
nexo-auth、nexo-im-api)统一接入@cmtlyt/logger,由后端通用 SDK 统一提供与配置,不各自初始化 - 以下关键事件必须产生结构化日志:登录成功与失败、授权码签发与兑换、令牌续期、设备吊销、吊销通知的投递结果、WebSocket 连接建立与断开
- 每条日志可关联到具体用户与设备(使用脱敏标识),支撑"某人某设备为什么掉线"这类排查
- 日志中不得出现明文密码、完整访问令牌、刷新令牌
- 本期只覆盖后端;前端统一日志接入不在本期
FR-8 工程规范与部署分发文档
- 后端目录规范:
nexo-auth按routes/{模块}/{controller,routes,schema,service}+src/services存放跨模块通用逻辑 的结构落地,并沉淀为一份规范文档 - 后端通用 SDK:两个后端共享的 JWT 验签、公钥拉取与缓存、日志、错误处理抽为独立包
- 后端部署文档:
nexo-auth上线所需的 compose 条目、域名与反代配置、环境变量、数据库初始化与迁移步骤 - 前端部署文档:壳的 Web 版与
nexo-im-pc的构建期变量、部署目标,以及新增回调地址时需要同步登记到认证中心白名单的位置 - 桌面包分发:两个平台的安装包从哪个地址获取、版本如何标注、发布后如何通知团队更新。分发渠道未定则 FR-6 不算交付——包构建出来没人拿得到,等于没做
4. 明确不做(Out of Scope)
- 应用注册表(多子应用列表、侧边栏切换、多 iframe 生命周期管理)——顺延 2026-08-30
- agent 应用及壳与子应用之间的双向 RPC 契约——顺延
- 前后端 SDK 的正式包发布与版本管理(本期只要求可用,不要求发包)
nexo-im-api存量目录结构重构(本期只在新仓库确立规范)- 前端统一日志接入与日志上报(本期日志只覆盖两个后端,见 FR-7)
- Linux 桌面包、代码签名与公证、应用内自动更新(macOS 与 Windows 包本期交付,但均为未签名产物)
- 移动端
- 验收用例自动化(Playwright E2E)——顺延
- OIDC 完整合规、第三方 IdP 接入、开放注册、扫码登录、新设备登录确认
- 上一迭代顺延的 3 条 IM 消息层欠账(见第 2 节)
5. 非功能需求
- 认证中心与 IM 使用同一 PostgreSQL 实例的不同 database,服务重启不丢会话
- 资源服务验签为本地操作,不因认证中心短暂不可用而拒绝已签发的有效令牌
- 设备吊销从操作到生效 ≤ 5s
- 规模按 5 人设计,单实例部署
- 密码不得出现在认证中心以外的任何服务、日志或客户端存储中
6. 验收标准
见同目录 TC 文档。用例数量按 45 分钟验收窗口控制;标记为「可离线核验」的用例需在会前跑完并附证据,会上不占时间。
7. 风险与降级
| 风险 | 降级预案 |
|---|---|
| 认证链路未按期打通,桌面包挤占时间 | 桌面壳降级为「仅加载远程 Web 壳」,放弃本地回环回调与系统凭证库存储,认证链路优先保证 |
| CI 构建矩阵在某一平台卡住(工具链差异、原生依赖编译失败) | 优先保证团队成员各自主力系统的包可用;实在拉不通的那个平台降级为 0830 交付,并在验收会上说明卡点,不拿整条 FR-6 陪绑 |
| 自研授权码流程存在安全实现缺陷 | 评审时对照 RFC 逐项自查:授权码一次性、回调地址精确匹配、PKCE 校验、state 绑定、刷新令牌轮换与复用检测 |
users / devices 迁移导致现有账号不可用 | 迁移脚本先在本地与预发跑通并保留回滚脚本;种子账号可重建,无真实业务数据 |
| 桌面端本地回环端口被占用或被安全软件拦截 | 端口随机化并重试;失败时回退为系统浏览器登录后手动确认 |
8. Roadmap(不进本期,仅登记)
按当前认知登记的中长期需求,具体分期在后续迭代评审时确定:
- 系统消息推送、消息读写状态、消息确认机制
- MQ 中间件、Redis
- 心跳与连接健康度(断线重连已于 2026-08-16 交付)
- 传输层加密强化、端到端聊天加密
- 客户端本地存储与离线可用
- 多媒体资源传输(图片、文件、语音、视频)
- 群聊与临时群组、AI 需求澄清与 agent 协作闭环
9. 约束与说明
- 本文档只定义"做什么";令牌载荷结构、表结构、吊销通道协议等属技术方案,由研发评审确定
- 迭代目录以验收会日期命名(
YYYY-MM-DD) - 本文档需经研发评审后方可拆解为 issue,issue 统一挂 GitHub org project 供认领
- 节奏:08-17 定稿 → 08-18 上午研发评审并拆 issue → 08-18 至 08-22 开发 → 08-22 下午预跑 TC → 08-23 会上 45 分钟验收 + 15 分钟确定下期