Skip to content

访问控制:用户、角色、API 令牌与审计 ​

Console 的账号存在网关自己的 .zhin/gateway.db 里,不在项目数据库(ADR 0049、ADR 0059),由管理网关负责登录与鉴权(ADR 0054)。实例停止或崩溃时这些页面照常可用。

侧栏「访问控制」分组有四个页面:用户(/access/users)、角色(/access/roles)、API 令牌(/access/tokens)、审计日志(/access/audit)。查看需要 iam.view,修改需要 iam.manage——内置角色里只有 owner 持有 iam.manage,admin 只有 iam.view;没有 iam.manage 时页面只读。没有 iam.view 的账号看不到这个分组。删除、禁用、吊销会先确认,删除用户或角色要输入名称。

这里的「角色」是 Console 账号的角色,决定谁能在 Console 里做什么;对象页「角色」页签管理的是聊天角色(所有者 / 管理员 / 受信任),决定谁能在聊天里使用机器人的功能,两者互不影响(见聊天角色)。每个人改自己的密码、签发自己的 API 令牌在个人设置(/account,顶栏用户名进入)。

凭据 ​

凭据怎么得到用在哪里
初始化令牌配置里的 http.token(脚手架写入 .env 的 HTTP_TOKEN)只在还没有所有者时用于初始化向导(引导);创建所有者后在所有接口上返回 401
会话令牌用户名 + 密码登录(POST {base}/auth/login)浏览器里的 Console。默认 12 小时滑动过期、最长 30 天
API 令牌用户签发(见下文)CI、监控、zhin doctor --live、MCP / A2A 客户端;命令行从 ZHIN_CONSOLE_TOKEN 读取

既没有 http.token 也还没有所有者时,Host 处于开放模式,拥有全部权限,只接受回环地址、且不带 X-Forwarded-For / Forwarded 的请求(地址未知的请求不算本机)。http.host 是非回环地址(如容器里的 0.0.0.0)时网关拒绝以开放模式启动:先用 zhin doctor --fix 在 .env 生成 HTTP_TOKEN 并在配置里写 http.token: ${HTTP_TOKEN},或先 zhin console init 创建所有者。同机反向代理若不加转发头,开放模式下所有经代理的请求都会被当作本机——放在反向代理后面时务必设置初始化令牌。

所有凭据都以 Authorization: Bearer … 发送,不使用 Cookie。登录失败统一返回 401,同一 IP 与用户名 15 分钟内失败 5 次后指数退避(429)。

用户 ​

列出全部用户:用户名、显示名、角色、状态与密码修改时间。每行的「管理」菜单里有「修改显示名」「角色绑定」「重置密码」「禁用 / 启用」「删除」。

操作RPC权限
查看列表iam.users.listiam.view
新建用户(用户名小写唯一,密码至少 10 位)iam.users.createiam.manage
修改显示名(用户名用于登录,创建后不能修改)iam.users.updateiam.manage
禁用 / 启用iam.users.disableiam.manage
删除iam.users.deleteiam.manage
重置密码iam.users.reset-passwordiam.manage
修改角色绑定iam.bindings.setiam.manage
  • 改密码、禁用或删除用户后,该用户的全部会话立即失效;禁用或删除还会让他签发的 API 令牌失效。
  • 上述操作和改动角色绑定都会让他在实例上打开的事件流与 WebSocket 随即断开(之后按新权限重新连接);绑定变化对后续请求立即生效,因为每个请求都按当前绑定授权。
  • 系统里始终至少保留一个未禁用、拥有全局 owner 绑定的用户:删除、禁用或降级最后一个所有者会被拒绝。
  • 每个用户可以在「个人设置」里改自己的密码(POST {base}/auth/password)。

角色绑定与作用域 ​

一个绑定 = 角色 + 作用域:

作用域写法覆盖范围
全局—一切
适配器适配器实例别名,如 qq该适配器及其下全部账号
账号<别名>/<endpointId>,如 qq/bot-1只有该账号

只有 endpoint.view、endpoint.operate、endpoint.manage、feature.configure、feature.toggle 会按作用域收窄;其他权限只认全局绑定。例如「只管 Telegram 的运营」:给他绑定 operator,作用域选适配器 tg-main。

角色 ​

内置角色不能删改,可以复制后再改:

角色权限
owner全部(含 ops.terminal、iam.manage)
admin除 ops.terminal、ops.database.schema、iam.manage 外的全部
operatorstatus.view、endpoint.view、endpoint.operate、feature.view、feature.configure、feature.toggle、agent.view、ops.schedule.read、plugin.perms.read、plugin.perms.operate
viewer所有 *.view 与 *.read,不含 ops.config.read、ops.env.read(可能含机密)
操作RPC权限
查看角色与插件权限目录iam.roles.listiam.view
新建 / 修改 / 删除自定义角色iam.roles.create / iam.roles.update / iam.roles.deleteiam.manage

权限目录 ​

权限覆盖
status.view首页、系统状态、日志、能力浏览、命令权限说明、对象页「记录」页签、事件流、实例状态与日志
endpoint.view / endpoint.operate / endpoint.manage账号与会话读取 / 发消息、处理请求、登录辅助 / 增删改启停账号连接
feature.view / feature.configure / feature.toggle读取功能配置 / 写配置与覆盖 / 适配器、账号、会话层的启用禁用(见功能与三级配置)
plugin.manage安装、更新、卸载插件与依赖;插件全局启停(disable_plugins,网关事务);引导第 3–5 步
agent.view / agent.configureAI 与 Agent 读取 / 写入
ops.config.read / ops.config.write原始配置文件
ops.env.read / ops.env.write环境变量文件:读取(只有打码值)/ 保存;逐个显示原文(env:reveal)两个都要,并写入审计
ops.database.read / ops.database.write数据库浏览(按列排序、筛选,查看表结构与结构变更预览)/ 记录增删改
ops.database.schemaSQL 控制台(只读查询与写 SQL)与表结构调整(加/改名/删列、改类型、建表、索引);默认只有 owner 拥有,每条语句(字面量已脱敏)写入审计。见数据库
ops.schedule.read / ops.schedule.write定时任务(指定 IM 投递目标时还需目标账号上的 endpoint.operate)
ops.files.read / ops.files.write项目文件(读写配置文件仍需要 ops.config.*;.env / .env.* 不经项目文件读写,改在环境变量页 /ops/env 用 ops.env.* 管理)
ops.restart实例起停与重启
ops.terminal终端(见运维)
iam.view / iam.manage本分组;iam.manage 还管对象页「角色」页签(chat-roles.*,按作用域检查)
mcp.access / a2a.accessMCP Server、A2A Server 的 Bearer 访问
plugin.perms.read / plugin.perms.operate / plugin.perms.manage按级别授予全部插件权限

每个 Console RPC、每条 {base} HTTP 路由、每个由 Host 鉴权的 WebSocket 都登记在 @zhin.js/console-protocol 的权限表(CONSOLE_RPC_PERMISSIONS、CONSOLE_HTTP_PERMISSIONS、CONSOLE_WS_PERMISSIONS)里;没登记的对所有已登录主体一律拒绝。

插件权限 ​

插件自己的权限名形如 <插件>:<动作>(onebot11:read、ambient:read、ops:approve),属于 read / operate / manage 三级之一,由插件在 definePluginConsoleRpc({ permissions }) 里声明;没声明时按后缀推断(:read / :view → read;:approve / :manage / :admin / :write / :config → manage;其余 → operate)。

  • viewer 得到 read 级,operator 得到 read + operate,admin 与 owner 得到全部。
  • 自定义角色可以勾选级别权限,也可以直接列出插件权限名。当前没有插件使用的名字也能保存(插件可能还没装),保存结果带 warnings,在有插件用到它之前它不放行任何东西。
  • 角色编辑器里,每个角色显示实际生效的插件权限及来源(level / explicit),以及已加载插件的权限目录(来自实例;实例离线时网关沿用上一份)。
  • 插件 Console RPC 按方法检查:方法自己声明的权限和所属页面的要求都要满足;都没声明时读方法需要 feature.view、动作需要 feature.configure。

API 令牌 ​

操作接口权限
我的令牌(个人设置 /account)GET / POST {base}/auth/tokens、POST {base}/auth/tokens/revoke已登录即可
全部令牌(可按用户筛选)iam.tokens.listiam.view
「为用户签发」/ 吊销iam.tokens.create / iam.tokens.revokeiam.manage

在 API 令牌页点「为用户签发」,选用户、填名称与有效期;在个人设置里签发自己的令牌也一样。Console 界面签发的令牌拥有该用户的全部权限;通过接口签发时可以只列出需要的权限(例如就绪探测只要 status.view,MCP 客户端只要 mcp.access),列表里显示为「收窄为 N 项」。

  • 明文只在签发时显示一次,库里只存 SHA-256。
  • 令牌的权限不超过签发用户:列出的插件权限只有用户自己(按名或按级别)持有时才生效;用户被禁用、删除时令牌一起失效;也可以单独吊销。
  • 命令行工具读 ZHIN_CONSOLE_TOKEN:ZHIN_CONSOLE_TOKEN=<令牌> zhin doctor --live https://bot.example.com/api --json。
  • MCP / A2A 客户端把令牌作为 Authorization: Bearer 发送;签发账号必须全局持有 mcp.access / a2a.access(只在某个作用域内持有不算)。也可以改用协议自己的 mcp.token / a2a.token,见配置 · mcp / a2a。初始化令牌在首个所有者创建后失效,不能用于 MCP / A2A。

审计日志 ​

iam.audit.list(iam.view)分页列出 console_audit_log,可按主体、动作、时间过滤。

记录的事件说明
登录成功 / 失败、登出、改密码主体、IP
全部 iam.* 写操作用户、角色、绑定、令牌的变化
映射为写权限的 RPC实例侧的写操作由实例上报,网关写入
显示环境变量原文(env:reveal)文件、变量名、主体;不记录值
全部被拒绝的请求outcome: denied
终端会话开始 / 结束目标、时长、退出码与原因;不记录输入输出
  • 主体写作 bootstrap、user:<id>、api-token:<id>;detail 只记录 RPC 类型、目标与参数键名,不记录参数值与机密;env:reveal / env:save 另记文件名与涉及的变量名(set / deleted)。
  • 保留 180 天,按天清理。
  • 网关不读取 X-Forwarded-For:放在反向代理后面时,记录的 IP 是代理地址。

离线救援 ​

忘记密码或所有者被锁:在服务器上直接操作 .zhin/gateway.db(zhin console user …),不需要运行中的网关,也没有在线的超级凭据。

bash
zhin console user list
printf '%s\n' "$NEW_PASSWORD" | zhin console user passwd alice --password-stdin
zhin console user enable alice
printf '%s\n' "$PASSWORD" | zhin console user create rescue --role owner --password-stdin

zhin console user create 不带 --role 时为 viewer。

相关 ​