跳转到内容

管理后台 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只读 权限,按需覆盖 dashboardlogsusers 等模块;需要写操作时再加对应的 .write 或完整 admin.<模块>。只读场景下,许多接口还会对敏感字段 脱敏(见下文「只读操作员与敏感数据」)。

协作结束后,具备 admin.operators.write 的管理员可以 停用或删除 该操作员,或 收紧权限;对方需 重新登录 后 JWT 才会反映变更。系统不会替你「自动到期」,权限边界由你通过账号与权限串显式控制。

操作员 JWT(以及 D1 表 t_admin_operator.permissions)里是一个 JSON 字符串数组

常见形式:

  • admin.<module> — 该模块读写类能力全开(与早期数据兼容)。
  • admin.<module>.read — 仅允许查询类管理接口。
  • admin.<module>.write — 允许变更类接口;具体路由在 Worker 侧标注为 readwrite
  • "*" — 操作员超级权限(仍非 Legacy 密钥登录)。

<module> 必须与后端目录一致,例如:

dashboarduserscreditsprojectskeyslogsverificationsguestsoauthreferralsoperators,以及跨服务的 paysupportblognotifycdnsitepromptcheckinprovidercore 等。

模板仓库中的权威定义见:

  • backend/node1-auth-service/src/constants/admin-permissions.ts(常量)
  • 同文件内 ADMIN_ROUTE_ACCESS:每个 POST /admin/... 路径对应 { module, need: 'read' | 'write' }
  1. node1-auth-service:除登录、/admin/me 等外,对 /admin/* 校验 JWT;操作员须满足该路径要求的模块与读/写级别。
  2. 其他 Worker(支付、工单、签到、provider 等):通过 Service Binding 调 auth 或本地校验,权限串与上表同一套。
  3. 管理端前端(nuxt-admin-layer:用 canReadModule / canWriteModule 控制按钮与入口;若直接调 API,仍以服务端 403 与脱敏为准

当某模块仅有 .read、没有 .write 且没有裸的 admin.<module> 时,许多列表/详情接口会对响应做 脱敏(邮箱掩码、密钥占位等)。实现集中在模板仓库的 packages/backend-utils/src/admin-sensitive-redact.ts,按接口汇总的说明见 docs/rbac/redaction.md

前置条件

  • 已执行 D1 迁移,存在表 t_admin_operator(模板中 backend/node1-auth-service/migrations/0011_admin_operators.sql)。

通过管理界面(推荐)

  1. 使用 LegacyADMIN_SECRET)登录,或已具备 admin.operators(或 *)的操作员登录。
  2. 打开 管理员账号 / Admin operators(继承 nuxt-admin-layer 的应用一般为路由 /operators)。
  3. 新建:填写 邮箱密码(长度需满足接口校验),并勾选 权限(与权限目录一致)。

只有 ADMIN_SECRET 时如何起步

  1. 先用密钥登录一次。
  2. 管理员账号 页面创建实际操作员;日常尽量用操作员登录,密钥仅作备用。

通过 SQL 手工插入(高阶)

若必须手写首条记录:password_hash 须与 node1-auth-servicehashPassword(见 src/utils/password.ts)一致;permissions 为合法 JSON 数组字符串,例如 ["admin.dashboard","admin.users.read"]。哈希或 JSON 错误会导致无法登录。能走界面尽量走界面。

  • admin.operators.read — 可列出操作员。
  • admin.operators.write — 可创建、更新、停用/删除操作员。

没有 admin.operators(且无 *、非 Legacy)时,不应能打开操作员管理页或调用对应 API。

继承 nuxt-admin-layer 的应用侧栏 「后台管理 / Admin」 分组中通常包含:

  • 管理员账号 — 路由 /operators,维护操作员账号(需 admin.operators)。
  • 管理平台设置 — 路由 /login-settings,配置管理后台公网地址、邮件魔法链接与客户演示链接(与操作员管理同属 operators 模块权限)。
  • 管理后台公网地址 — 保证魔法链接邮件、演示链接预览里的 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(密码、魔法链接、演示链接)均在 签发时 写入权限;在界面里 修改 某操作员权限后,已持有的 JWT 不会自动更新,需重新登录、重新点邮件链接或重新用演示 token 兑换,直至旧 JWT 过期。
  • 吊销 某条客户演示链接后,由该链接签出的、带 demo_link_id 的会话会在服务端立即失效(下一次请求即 401)。
  • 演示链接若 绑定高权限操作员,相当于向对方发放接近该账号能力的长期会话(演示 JWT 有效期往往较长),对外演示时尽量使用 权限范围小 的专用操作员。
  • 经典 演示 URL 默认不是「一次性」的;在未吊销、未过期前,同一 demo_token重复兑换,请按需控制传播范围。
  • 操作员表:0011_admin_operators.sql
  • 演示链接表:0014_admin_demo_link.sql
  • 演示链接可选绑定操作员:0015_admin_demo_link_operator.sqladmin_operator_id 列)
  • 对外包或客服优先给 细粒度 权限(大量 *.read + 少量 *.write),避免滥用 *
  • Legacy 密钥不受 RBAC 限制,泄露等于全盘失控;泄露后请轮换 ADMIN_SECRET 并审计操作员列表。
  • 修改权限后,操作员通常需要 重新登录 以刷新 JWT。
  • 06. 首次初始化你的系统 — 首次用 ADMIN_SECRET 登录
  • 模板说明:backend/node1-auth-service/README.md(多管理员与 RBAC 小节)
  • 模板说明:docs/rbac/redaction.md(只读脱敏对照表)