从单用户 Chat 到多租户服务:mini-agent 隔离改造复盘
原来的系统默认只有一个人
mini-agent 最初服务的是一个明确的使用者:本地机器上的 Telegram、个人任务和个人对话。Web Chat 虽然已经有密码和 token,但它依旧建立在“拿到这把密码的人就是同一个人”的假设上。对个人工具来说,这很省事;对公网入口来说,它会让会话、执行环境和资源消耗都失去归属。
把入口改成邮箱、密码和邀请码,只解决了第一屏。真正的改造是让后端从 token 中恢复用户 ID 和角色,并将这份身份带到历史查询、任务执行、文件挂载和配额统计。关于这条链如何实现,单独整理在《mini-agent 多租户隔离技术详解》。这篇文章只讨论另一件同样容易做乱的事:本地、ECS、Web 和 APK 到底各自负责什么。
一份后端策略,三个不同的入口
- 打开职责边界图 — 支持暗亮主题切换和 PNG/JPEG/WebP/SVG 导出
图里最重要的不是线有多少,而是谁不做什么。
- 本地实例保留 Telegram、调度和个人自动化任务。它是主动方,继续适配家用机器的使用方式。
- ECS承载面向公网的多用户 Web API。身份认证、角色授权、工作区隔离和配额限制都在这里执行,因为这里面对的是不可信请求。
- 博客 Chat 页是普通用户可访问的交互入口:登录、邀请码注册、会话恢复、错误提示和角色化界面。
- APK被收敛为管理员客户端:连接管理、管理员身份提示和一次性邀请码管理。
这不是高可用集群。若本地实例停止,Telegram 和调度任务不会自动迁移到 ECS;ECS 提供的是独立的公网 API 入口,而不是业务层的热备。这个限制决定了故障预期,也避免把“有两台机器”误读成“业务自动接管”。
为什么租户隔离只放在 ECS 后端
Web 页面和 APK 都能隐藏按钮、保存 token、显示用户资料,但它们不拥有可信身份。浏览器的 localStorage 可以被修改,APK 的界面状态也不能作为授权依据;甚至一个请求 body 中的 user_id 都不应该被服务端直接相信。
真正的权限判断集中在 ECS 的 Web API:
- Bearer token 在认证中间件中还原为
request["user"] = {"id", "role"}。 - 角色守卫决定
/admin/*、待办、日程和话题能力是否允许访问。 - 会话线程使用用户前缀,历史查询按当前用户过滤。
/query和/task根据用户 ID 选择data/workspaces/<user_id>,再传入bwrap。- 配额中间件按用户的日桶原子预留调用次数,并在执行后累计
pi_seconds。
前端对这些策略的职责是表达,不是复制。这样同一条后端规则可以同时约束博客 Chat 页、APK 和未来的其他客户端;某个客户端漏了一个显隐条件,安全边界也不会跟着消失。
博客 Chat 页:把服务端结果变成可用交互
博客 Chat 页是唯一面向普通用户开放的界面,因此它要处理最完整的账户流程:邮箱密码登录、邀请码注册、登出以及会话恢复。恢复时页面会请求 /auth/status,以服务端返回的角色和用户 ID 为准,而不是只读取缓存的 token。
登录后的差异也保持克制。普通用户可以对话、查询和执行任务;管理员才会看到待办、日程、话题和管理面板。管理面板调用后端 /admin/* 端点生成邀请码、查看用户、封禁账号。页面收到 401 时回到登录状态,收到 403 显示无权限,收到 429 显示当日额度已耗尽。
这些状态映射有两个好处。第一,普通用户不需要理解内部管理能力;第二,错误不会被混成“网络坏了”或“密码错了”。但它们仍是体验层:请求是否真能执行,由服务端中间件和角色守卫决定。
APK:不重复做用户系统,只承担管理员操作
移动端没有复制完整的多租户账户中心。它默认服务管理员,因此登录改为邮箱和密码,设置页集中展示管理员身份、当前会话和连接信息,并提供一次性邀请码的生成、查看与复制。
这个定位是有意收窄,而不是缺功能。邀请码和用户管理天然属于高权限操作,移动端的目标是让管理员在需要时完成这些动作,而不是把 Web 的注册、用户列表和普通用户工作流再实现一遍。邀请码仍由后端创建和计数;APK 只是调用接口并展示结果。
聊天历史也要分清两类。APK 的会话列表和滚动记录保存在设备本地,用于切换本次或过去的本地聊天会话;云端租户隔离处理的是后端接收到请求后,如何给每个已认证用户分配线程、工作区和配额。两者解决的问题不同,不能互相替代。
为什么不让客户端各自实现一遍隔离
让 Web 和 APK 分别维护用户表、配额计数或租户过滤,看上去能“多一层保护”,实际会引入两份不一致的事实:两个端的时钟、规则、缓存和异常处理都可能不同。更糟的是,攻击者可以绕开客户端直接调用 API。
因此,系统把可信决策留在后端,客户端只做三件事:收集凭据、显示服务端确认后的状态、把明确的错误反馈给用户。这个分工让入口可以增加,授权规则却不需要随入口复制。
复盘:边界比功能更早定下来
多租户改造很容易被页面改造带着走:先做注册页、再做用户列表、最后才想起工作区和配额。实际顺序应该倒过来。先确定“用户身份进入后端后必须到达哪里”,再决定客户端需要展示什么。
本次改造的结果是一个明确的分工:本地保留个人自动化,ECS 承担不可信公网请求,Web 提供普通用户入口,APK 提供管理员操作,后端负责所有最终授权、资源边界和配额限制。详细的后端链路、真实字段名和关键伪代码见技术详解。
参考资料
- mini-agent 多用户认证、租户隔离与会话管理设计 — 多用户认证、线程、工作区、角色与配额的后端设计来源。
- mini-agent 多租户安全加固设计 — 多租户执行的文件系统边界与 fail-closed 约束。
- 博客 Chat 页多用户改造 — Web 的登录、注册、角色化界面、管理和配额提示实现。
- Android 管理员设置与邀请码设计 — APK 管理员设置与一次性邀请码能力的设计依据。