auth Plugin
详细说明 auth 内建 plugin 的职责、授权链路、角色解析方式、可调用动作,以及它和 guard、effect、resolve 的关系
auth Plugin
auth 是当前 Downcity 内建 plugin 里最“平台规则化”的一个。
它不是为了给 agent 增加某个业务功能,而是为了回答三个基础问题:
- 谁可以进入 chat 链路
- 平台已经观察到了哪些用户和 chat
- 某个用户当前的有效角色是什么
它到底做什么
auth 主要负责四件事:
- 在 chat 入站时做授权判断
- 记录观察到的用户和会话主体
- 解析用户在某个渠道中的角色
- 通过 action 暴露授权配置和快照读写能力
所以它横跨了:
- 入口守卫
- 运行观察
- 权限解析
- 控制面动作
为什么它是“特殊 plugin”
和其他大多数内建 plugin 不一样,auth 不是普通的可选插件。
它当前的可用性语义是:
enabled: trueavailable: true
也就是说,它始终被视为可用,不走常规的开关型生命周期。
这很合理,因为一旦把授权逻辑也做成“可随时完全失效的可选能力”,整个平台规则层就会变得不稳定。
它使用了哪些 plugin 能力
auth 用到的能力面是:
availabilityhooks.guardhooks.effectresolvesactions
它没有使用:
setupusagesystemhttp.runtime
这说明 auth 不是一个需要 UI 安装向导的插件,也不是一个主要靠 system prompt 提示词起作用的插件。
典型运行流
一个典型的 chat 消息进入系统时,auth 大致会按这个顺序参与:
- chat 入站流程触发授权检查点
auth的guard钩子根据渠道、chatId、userId 等信息判断是否放行- 如果不放行,链路直接报错并停止
- 如果放行,系统继续处理消息
- 后续的主体观察点会调用
effect,把用户 / chat 信息记入观察态 - 当下游需要知道“这个用户是什么角色”时,会调用
resolve
换句话说:
guard决定能不能进effect负责留下观察记录resolve提供角色答案
典型场景
场景一:只允许特定 Telegram 用户给 agent 发消息
你可以把授权配置写入 auth,然后所有 Telegram 入站消息都会先经过 guard。
如果用户不在允许名单里,消息不会进入后续 agent 执行阶段。
场景二:第一次接入某个群聊后,想知道系统已经观察到了哪些主体
这时可以通过 snapshot action 读取当前快照,查看:
- 已记录的用户
- 已记录的 chats
- 当前生效的授权配置
场景三:下游能力要根据用户角色决定是否放行
例如:
- 管理员可以使用高风险工具
- 普通成员只能执行只读任务
这时下游可以调用角色解析点,而不需要自己重复读授权存储。
在 SDK 里怎么挂载
import { Agent } from "@downcity/agent";
import { ChatAuthorizationPlugin } from "@downcity/plugins";
const agent = new Agent({
id: "chat-agent",
path: "/path/to/project",
tools: {},
plugins: [new ChatAuthorizationPlugin()],
});chat-authorization 本身更常被运行时自动消费,而不是像普通业务插件那样由你手动频繁调用。
可调用动作
chat-authorization 暴露了四个最核心的动作。
| Action | 作用 | 适合什么时候用 |
|---|---|---|
snapshot | 读取授权快照 | 想查看当前观测态和配置 |
readConfig | 读取授权配置 | 想做控制面展示或调试 |
writeConfig | 写入授权配置 | 想批量更新授权规则 |
setUserRole | 设置用户角色 | 想单独修改某个用户的角色 |
读取当前授权快照
const snapshot = await agent.plugins.runAction({
plugin: "auth",
action: "snapshot",
});这个结果通常会包含:
- 当前授权配置
- 已记录用户
- 已记录 chats
读取当前授权配置
const config = await agent.plugins.runAction({
plugin: "auth",
action: "readConfig",
});写入新的授权配置
const result = await agent.plugins.runAction({
plugin: "auth",
action: "writeConfig",
payload: {
config: {
telegram: {
enabled: true,
},
},
},
});为某个用户设置角色
const result = await agent.plugins.runAction({
plugin: "auth",
action: "setUserRole",
payload: {
channel: "telegram",
userId: "123456",
roleId: "admin",
},
});它和 Hook / Resolve 的关系
auth 是理解这些机制最典型的内建样本之一:
guard:阻止不该进入的消息effect:记录观察到的主体resolve:给出用户有效角色
如果你读完 auth 还对这些概念不够直观,建议继续看:
它和 runtime ownership 的边界
auth 不是一个长期持有连接或线程的 runtime owner。
它更像一层规则编排:
- 在关键点上挂规则
- 把底层授权配置与状态存储统一暴露出来
- 让别的能力通过标准接口读取角色结果
如果你把它当作长期运行实例,会很容易误以为“权限判断应该塞进某个长期运行实例内部”。当前设计恰恰避免了这种耦合。
需要注意的边界
它只处理 chat 授权与角色解析相关问题
auth 不是一个通用 ACL 系统,也不是任意资源访问控制框架。
它当前聚焦在 chat 渠道场景。
它依赖标准的渠道信息
当前渠道识别依赖的是标准 channel 值,例如:
telegramfeishuqq
如果传入了无效 channel,相关动作或 hook 会直接报错。
它不是 UI 配置型插件
你不会像 web、asr、tts 那样通过 setup / usage 去安装模型或切换 provider。
auth 的核心价值在规则判断,不在依赖安装。
什么时候优先参考它
当你要设计这些能力时,优先参考 auth:
- 入站守卫
- 用户 / 会话主体观测
- 角色解析
- 平台级规则型插件