管理后台 RBAC 与操作员账号
除 邮箱密码 与 Legacy 密钥 外,还支持 无密码 流程(邮件魔法链接、客户演示链接),最终仍签发常规管理端 JWT。详见下文「无密码登录与平台设置」一节。
ZShip 管理后台支持 两种登录方式:
| 方式 | 登录 | JWT 特征 | 典型用途 |
|---|---|---|---|
| Legacy 超级管理员 | POST /admin/login,body 为 { "secret": "<ADMIN_SECRET>" } | 无 admin_kind: "operator",无 permissions 数组 | 首次初始化、应急、全权限 |
| 操作员(RBAC) | POST /admin/login,body 为 { "email": "...", "password": "..." } | 带 admin_kind: "operator" 与 permissions: string[] | 日常运维、最小权限 |
下文主要说明 操作员 与权限如何生效。Legacy 密钥等价于根密码,务必严格保管 ADMIN_SECRET。

典型场景:只让人看运营,不让人改数据
Section titled “典型场景:只让人看运营,不让人改数据”如果你需要同事或合作方 了解系统运营情况(例如仪表盘、分析、日志、用户列表等),但 不希望 对方能随意 编辑、删除 业务数据或改动关键配置,请使用 操作员(RBAC) 账号,而不是把 ADMIN_SECRET 交给对方。
做法是:在 管理员账号 / Admin operators(一般为 /operators)里新建操作员,只勾选 admin.<模块>.read 等 只读 权限,按需覆盖 dashboard、logs、users 等模块;需要写操作时再加对应的 .write 或完整 admin.<模块>。只读场景下,许多接口还会对敏感字段 脱敏(见下文「只读操作员与敏感数据」)。
协作结束后,具备 admin.operators.write 的管理员可以 停用或删除 该操作员,或 收紧权限;对方需 重新登录 后 JWT 才会反映变更。系统不会替你「自动到期」,权限边界由你通过账号与权限串显式控制。
操作员 JWT(以及 D1 表 t_admin_operator.permissions)里是一个 JSON 字符串数组。
常见形式:
admin.<module>— 该模块读写类能力全开(与早期数据兼容)。admin.<module>.read— 仅允许查询类管理接口。admin.<module>.write— 允许变更类接口;具体路由在 Worker 侧标注为read或write。"*"— 操作员超级权限(仍非 Legacy 密钥登录)。
<module> 必须与后端目录一致,例如:
dashboard、users、credits、projects、keys、logs、verifications、guests、oauth、referrals、operators,以及跨服务的 pay、support、blog、notify、cdn、site、prompt、checkin、provider、core 等。
模板仓库中的权威定义见:
backend/node1-auth-service/src/constants/admin-permissions.ts(常量)- 同文件内
ADMIN_ROUTE_ACCESS:每个POST /admin/...路径对应{ module, need: 'read' | 'write' }。
校验发生在哪里
Section titled “校验发生在哪里”- node1-auth-service:除登录、
/admin/me等外,对/admin/*校验 JWT;操作员须满足该路径要求的模块与读/写级别。 - 其他 Worker(支付、工单、签到、provider 等):通过 Service Binding 调 auth 或本地校验,权限串与上表同一套。
- 管理端前端(
nuxt-admin-layer):用canReadModule/canWriteModule控制按钮与入口;若直接调 API,仍以服务端 403 与脱敏为准。
只读操作员与敏感数据
Section titled “只读操作员与敏感数据”当某模块仅有 .read、没有 .write 且没有裸的 admin.<module> 时,许多列表/详情接口会对响应做 脱敏(邮箱掩码、密钥占位等)。实现集中在模板仓库的 packages/backend-utils/src/admin-sensitive-redact.ts,按接口汇总的说明见 docs/rbac/redaction.md。
新增管理员账号(推荐流程)
Section titled “新增管理员账号(推荐流程)”前置条件
- 已执行 D1 迁移,存在表
t_admin_operator(模板中backend/node1-auth-service/migrations/0011_admin_operators.sql)。
通过管理界面(推荐)
- 使用 Legacy(
ADMIN_SECRET)登录,或已具备admin.operators(或*)的操作员登录。 - 打开 管理员账号 / Admin operators(继承
nuxt-admin-layer的应用一般为路由/operators)。 - 新建:填写 邮箱、密码(长度需满足接口校验),并勾选 权限(与权限目录一致)。
只有 ADMIN_SECRET 时如何起步
- 先用密钥登录一次。
- 在 管理员账号 页面创建实际操作员;日常尽量用操作员登录,密钥仅作备用。
通过 SQL 手工插入(高阶)
若必须手写首条记录:password_hash 须与 node1-auth-service 的 hashPassword(见 src/utils/password.ts)一致;permissions 为合法 JSON 数组字符串,例如 ["admin.dashboard","admin.users.read"]。哈希或 JSON 错误会导致无法登录。能走界面尽量走界面。
operators 模块本身
Section titled “operators 模块本身”admin.operators.read— 可列出操作员。admin.operators.write— 可创建、更新、停用/删除操作员。
没有 admin.operators(且无 *、非 Legacy)时,不应能打开操作员管理页或调用对应 API。
无密码登录与平台设置
Section titled “无密码登录与平台设置”在界面中的位置
Section titled “在界面中的位置”继承 nuxt-admin-layer 的应用侧栏 「后台管理 / Admin」 分组中通常包含:
- 管理员账号 — 路由
/operators,维护操作员账号(需admin.operators)。 - 管理平台设置 — 路由
/login-settings,配置管理后台公网地址、邮件魔法链接与客户演示链接(与操作员管理同属operators模块权限)。
「平台设置」里有什么
Section titled “「平台设置」里有什么”- 管理后台公网地址 — 保证魔法链接邮件、演示链接预览里的
https://…正确;数值可来自数据库设置与/或认证 Worker 环境变量ADMIN_PUBLIC_ORIGIN(参见 绑定域名和环境变量)。 - 邮件魔法链接 — 开启后,用户在登录页填写 已注册的操作员邮箱 可申请 一次性 邮件登录链接。后端按
t_admin_operator匹配邮箱,验证后签发admin_kind: "operator"的 JWT,与密码登录在 RBAC 上等价。 - 客户演示链接 — 长期有效的 免密 链接(管理后台登录页通过
?demo_token=使用)。创建时可二选一:- 经典演示 — 内部演示身份(
admin_kind: "demo"),权限写在演示链接记录上(默认多为仪表盘只读)。 - 绑定操作员(可选) — 绑定 启用中 的操作员;兑换 token 时按 当时 该账号的权限签发 操作员 JWT,并在 JWT 中携带
demo_link_id,吊销该演示链接后,下一次 受保护的 API 请求即被拒绝(无需等 JWT 自然过期)。
- 经典演示 — 内部演示身份(
JWT 与权限变更
Section titled “JWT 与权限变更”- 各类管理端 JWT(密码、魔法链接、演示链接)均在 签发时 写入权限;在界面里 修改 某操作员权限后,已持有的 JWT 不会自动更新,需重新登录、重新点邮件链接或重新用演示 token 兑换,直至旧 JWT 过期。
- 吊销 某条客户演示链接后,由该链接签出的、带
demo_link_id的会话会在服务端立即失效(下一次请求即 401)。
- 演示链接若 绑定高权限操作员,相当于向对方发放接近该账号能力的长期会话(演示 JWT 有效期往往较长),对外演示时尽量使用 权限范围小 的专用操作员。
- 经典 演示 URL 默认不是「一次性」的;在未吊销、未过期前,同一
demo_token可 重复兑换,请按需控制传播范围。
相关 D1 迁移(node1-auth-service)
Section titled “相关 D1 迁移(node1-auth-service)”- 操作员表:
0011_admin_operators.sql - 演示链接表:
0014_admin_demo_link.sql - 演示链接可选绑定操作员:
0015_admin_demo_link_operator.sql(admin_operator_id列)
- 对外包或客服优先给 细粒度 权限(大量
*.read+ 少量*.write),避免滥用*。 - Legacy 密钥不受 RBAC 限制,泄露等于全盘失控;泄露后请轮换
ADMIN_SECRET并审计操作员列表。 - 修改权限后,操作员通常需要 重新登录 以刷新 JWT。
- 06. 首次初始化你的系统 — 首次用
ADMIN_SECRET登录 - 模板说明:
backend/node1-auth-service/README.md(多管理员与 RBAC 小节) - 模板说明:
docs/rbac/redaction.md(只读脱敏对照表)