hyapp-server/server/admin/docs/权限管理.md
2026-07-16 18:51:58 +08:00

24 KiB
Raw Blame History

HYApp 管理后台权限管理功能文档

本文档作为后台管理系统权限管理的设计基准。以后后台相关文档统一放在 hyapp-admin-server/docs/

目标

后台权限采用 RBAC

  • 用户通过角色获得权限,不直接给用户绑定权限。
  • 菜单权限控制页面入口和前端路由访问。
  • 按钮权限控制页面内操作按钮、批量操作、导出、状态变更等动作。
  • 后端接口必须做权限校验,前端按钮隐藏或禁用只作为体验层控制。
  • 权限码是前后端契约,不能只改文案或按钮,不同步后端权限码。

当前实现事实

当前后端已经具备基础 RBAC 表:

  • admin_users:后台用户。
  • admin_roles:后台角色。
  • admin_permissions:权限定义,字段包含 codenamekind
  • admin_user_roles:用户角色关系。
  • admin_role_permissions:角色权限关系。
  • admin_menus:菜单定义,通过 permission_code 绑定菜单查看权限。

当前认证链路:

  • 登录成功后,后端把用户权限码写入 access token。
  • 前端 AuthProvider 保存 permissions,通过 can(code) 判断。
  • 前端路由使用 RequirePermission 拦截页面。
  • 后端 API 使用 middleware.RequirePermission(code) 校验。

当前注意点:

  • 角色权限变更后,旧 access token 内的权限不会立即变化;用户重新登录或 refresh 后才会获得新权限。若后续需要立即生效,需要增加 session 失效或 token version 机制。
  • platform-admin 当前会绑定全部权限;其他预置角色需要补默认权限绑定策略。
  • 菜单权限 页面当前只读,没有菜单、权限定义的增删改能力。

用户 App 可见范围

角色权限决定“能做什么”,用户 App 范围决定“能在哪个 App 中做”。两者必须同时满足:

  • admin_users.app_scope_mode=all:主后台可以切换所有当前启用 App。
  • selected:只允许切换 admin_user_app_scopes 中显式绑定的 App。
  • none:主后台不发送 X-App-Code,只能进入通用工作台;财务工作台和运营工作台入口仍按 finance:viewoverview:view 控制。
  • 财务工作台的 App/区域数据范围继续由 admin_user_money_scopes 管理,不能与主后台 App 范围合并。
  • App 级 API 除角色权限外还必须通过后端 App scope 中间件校验,不能只依赖前端隐藏下拉项。

权限类型

权限 kind 使用以下值:

kind 用途 示例
menu 页面入口、路由访问、菜单展示 user:view
button 页面按钮、批量操作、导出、状态变更 user:create
api 独立接口权限。只有当接口不能自然归属到菜单或按钮时才使用 search:global

约定:

  • 普通页面查看权限统一使用 模块:view
  • 创建使用 模块:create
  • 编辑使用 模块:update
  • 删除使用 模块:delete
  • 导出使用 模块:export
  • 状态切换使用 模块:status
  • 批量操作如果风险高于单条操作,单独定义 模块:batch-*
  • 不再新增过宽的 *:manage 权限;当前已有 role:manage 可兼容保留,后续应拆到按钮级权限。

后台基础权限矩阵

总览

权限码 kind 控制范围 后端接口
overview:view menu 总览页面、总览菜单 GET /api/v1/dashboard/overview

按钮:

按钮 权限码 当前状态 目标
刷新 overview:view 已实现 查看总览即可刷新
部署服务 service:create 按钮已展示但未接动作 跳转或打开服务创建抽屉

服务管理

权限码 kind 控制范围 后端接口
service:view menu 服务管理菜单、列表、详情 GET /api/v1/servicesGET /api/v1/services/:id
service:create button 创建服务、总览部署服务 POST /api/v1/services
service:update button 编辑服务基础信息、配置 PATCH /api/v1/services/:id
service:operate button 启动、停止、重启 PATCH /api/v1/services/:id/statusPOST /api/v1/services/:id/restart

按钮:

页面 按钮 权限码 当前状态 目标
总览 部署服务 service:create 缺少动作 接入服务创建
总览/服务管理 启动 service:operate 已按权限控制 保持
总览/服务管理 停止 service:operate 已按权限控制 保持
总览/服务管理 重启 service:operate 已按权限控制 保持
服务管理 创建服务 service:create 已按权限控制 保持
服务管理 编辑服务 service:update API 已有,页面未接 新增编辑入口
服务管理 更多 按具体动作拆分 当前无实际动作 有动作后再展示

用户管理

权限码 kind 控制范围 后端接口
user:view menu 用户管理菜单、列表、详情 GET /api/v1/usersGET /api/v1/users/:id
user:create button 新增后台用户 POST /api/v1/users
user:update button 编辑后台用户姓名、团队、MFA、角色 PATCH /api/v1/users/:id
user:status button 启用、停用、锁定、解锁、批量状态 PATCH /api/v1/users/:id/statusPOST /api/v1/users/batch/status
user:reset-password button 重置后台用户密码 POST /api/v1/users/:id/reset-password
user:export button 导出后台用户 CSV GET /api/v1/users/export

按钮:

按钮 权限码 当前状态 目标
新增用户 user:create 已按权限控制 保持
编辑 user:update 已按权限控制 保持
锁定/解锁 user:status 已按权限控制 保持
启用/停用 user:status 已按权限控制 保持
批量启用/停用 user:status 已按权限控制 后续可拆 user:batch-status
重置密码 user:reset-password 已按权限控制 保持
导出 user:export 当前使用 user:view,前端按钮未单独控制 拆独立导出权限
角色配置快捷入口 role:view 已按权限控制 保持

角色管理

当前后端使用 role:viewrole:manage,目标需要拆细。

权限码 kind 控制范围 后端接口
role:view menu 角色配置菜单、角色列表 GET /api/v1/roles
permission:view menu 权限定义列表 GET /api/v1/permissions
role:create button 新增角色 POST /api/v1/roles
role:update button 编辑角色名称、编码、说明 PATCH /api/v1/roles/:id
role:delete button 删除角色 DELETE /api/v1/roles/:id
role:permission button 配置角色权限 PUT /api/v1/roles/:id/permissions
role:manage button 兼容旧权限 当前已实现,后续拆分后保留迁移期

按钮:

按钮 权限码 当前状态 目标
新增角色 role:create 当前使用 role:manage 拆为 role:create
编辑角色 role:update 当前使用 role:manage 拆为 role:update
删除角色 role:delete 当前使用 role:manage 拆为 role:delete
勾选权限 role:permission 当前跟随编辑角色保存 拆为角色授权权限

菜单权限

当前页面只读,目标需要支持菜单树维护和权限定义查看。

权限码 kind 控制范围 后端接口
menu:view menu 菜单权限页面、菜单树查看 当前用 GET /api/v1/navigation/menus
menu:create button 新增菜单 待新增
menu:update button 编辑菜单标题、路由、图标、权限码 待新增
menu:delete button 删除菜单 待新增
menu:sort button 菜单排序 待新增
menu:visible button 菜单显示/隐藏 待新增
permission:create button 新增权限定义 待新增
permission:update button 编辑权限名称、类型、说明 待新增
permission:delete button 删除未绑定权限 待新增
permission:sync button 从代码或配置同步权限种子 待新增

按钮:

按钮 权限码 当前状态 目标
新增菜单 menu:create 未实现 新增
编辑菜单 menu:update 未实现 新增
删除菜单 menu:delete 未实现 新增
上移/下移 menu:sort 未实现 新增
显示/隐藏 menu:visible 未实现 新增
新增权限 permission:create 未实现 新增
编辑权限 permission:update 未实现 新增
删除权限 permission:delete 未实现 新增
同步权限 permission:sync 未实现 新增

日志审计

权限码 kind 控制范围 后端接口
log:view menu 登录日志、操作日志页面 GET /api/v1/logs/loginGET /api/v1/logs/operations
log:export button 导出日志 待新增

按钮:

按钮 权限码 当前状态 目标
搜索 log:view 已实现 保持
导出 log:export 未实现 新增
查看详情 log:view 未实现 新增详情抽屉

个人账户

个人账户操作不走角色授权,登录用户默认可操作自己的会话和密码。

功能 权限 后端接口 当前状态
查看自己 登录态 GET /api/v1/auth/me 已实现
修改自己的密码 登录态 POST /api/v1/auth/change-password API 已有,前端入口未实现
退出登录 登录态 POST /api/v1/auth/logout 已实现

全局搜索

当前搜索接口为登录态可用:GET /api/v1/search

目标:

  • 搜索结果必须按用户权限过滤。
  • 没有 service:view 时不返回服务结果。
  • 没有 user:view 时不返回用户结果。
  • 没有 role:view 时不返回角色结果。
  • 搜索结果跳转的目标页面必须有对应菜单权限。

App 业务后台权限预留

以下权限用于 App 业务管理模块。已接入默认菜单的模块由后台种子同步菜单、权限和平台管理员授权。

App 用户

权限码 kind 控制范围
app-user:view menu App 用户列表、详情
app-user:level button 临时调整 App 用户富豪/魅力等级
app-user:export button 按当前筛选条件异步导出 App 用户
app-user:update button 修改用户资料
app-user:status button 后台封禁、解封
app-user:password button 后台设置 App 用户密码
app-user:identity button 短号、靓号管理
app-user:country button 国家/区域调整

国家和区域

权限码 kind 控制范围
country:view menu 国家列表
country:create button 新增国家
country:update button 编辑国家
country:status button 启用、停用国家
region:view menu 区域列表
region:create button 新增区域
region:update button 编辑区域
region:status button 停用区域
region:countries button 维护区域国家

房间管理

权限码 kind 控制范围
room:view menu 房间列表、详情、房间状态
room:update button 后台修改房间展示资料、模式、状态、区域
room:delete button 后台删除房间
room-pin:view menu 房间置顶菜单、置顶列表
room-pin:create button 新增或恢复房间置顶
room-pin:cancel button 取消房间置顶
room-config:view menu 房间配置页面、读取座位数配置
room-config:update button 保存启用座位数和默认座位数
room:create button 后台创建房间
room:mic button 上下麦、换麦、锁麦
room:chat button 公屏开关
room:admin button 设置房间管理员
room:mute button 禁言、解除禁言
room:kick button 踢出房间
room:unban button 房间解封用户

文件上传

权限码 kind 控制范围
upload:create button 后台上传文件、图片到 COSobject key 使用后台独立前缀

钱包和交易

权限码 kind 控制范围
wallet:view menu 钱包概览、余额查询
wallet:transaction-view menu 交易流水
wallet:adjust button 后台调账
operations-withdrawal:view menu 用户提现运营审核列表;不包含 operations_status=skipped 的历史单
operations-withdrawal:audit button 运营初审;通过后转交财务,拒绝时释放冻结余额并终止流程
finance-withdrawal:view menu 用户提现财务审核列表;只包含运营已通过和 skipped 历史兼容单
finance-withdrawal:audit button 财务终审;通过时扣减 frozen拒绝时释放 frozen

两个提现工作台都以 admin_user_money_scopes 作为 App 数据范围:显式选择 App 时必须命中授权,未选 App 的列表只查授权 App 集合,仅 platform-admin 的全量资金范围可跨全部 App。审核请求必须显式携带目标行的 X-App-Code,后端会在钱包动作前再校验 MoneyAccess。GET /admin/finance/scope 仅返回这份授权目录,其读权限为 finance:viewfinance-withdrawal:view|auditoperations-withdrawal:view|audit,不因此赋予审核写权。

运营状态 rejecting 表示拒绝 claim 已独立提交、钱包释放或通知/终态收敛仍需重试。该状态只能继续调用原拒绝接口,后端沿用第一次审核人、原因和固定 command不能改点通过也不会进入财务列表。运营工作台必须显示“重试拒绝”不能把它当成普通 pending

用户提现两级审核发布顺序

102_user_withdrawal_operations_review.sql 不能和旧 admin 实例混跑。旧 admin 只识别总体 status=pending,会绕过 operations_status 直接调钱包终审。生产必须按以下顺序发布:

  1. 先执行 scripts/mysql/068_wallet_withdrawal_terminal_locks.sql,完成新 wallet-service 的全量滚动,确保所有钱包实例都能按申请 ID 收敛旧/新 command。
  2. 摘流所有旧 admin 实例,确认无旧版财务审核请求在飞。
  3. 执行 admin 102 迁移。迁移持久化当时的最大申请 ID仅把该范围内已经终审的历史行标记 skipped;尚未终审的 status=pending 申请和迁移后新申请都保持运营 pending
  4. 部署新 admin 并恢复流量,验证运营/财务列表和 MoneyAccess 隔离。
  5. 最后滚动 gateway。即使窗口内旧 gateway 不写 operations_status,数据库默认也会让新单进入运营待审。

礼物和活动

权限码 kind 控制范围
resource:view menu 资源列表、资源详情
resource:create button 新增资源
resource:update button 编辑资源、启用、禁用
resource-shop:view menu 道具商店售卖列表
resource-shop:update button 添加售卖资源、配置售卖天数和启用、禁用
resource-group:view menu 资源组列表、资源组详情
resource-group:create button 新增资源组
resource-group:update button 编辑资源组、替换组成员、启用、禁用
resource-grant:view menu 资源赠送记录
resource-grant:create button 给用户赠送资源或资源组
resource-grant:revoke button 撤销成功的资源组赠送
gift:view menu 礼物列表
gift:create button 从资源库选择资源新增礼物
gift:update button 编辑礼物、资源绑定和价格
gift:status button 上架、下架
gift:delete button 删除礼物列表配置
activity:view menu 活动列表
activity:create button 新增活动
activity:update button 编辑活动
activity:status button 发布、暂停、结束

主播、公会和 BD

权限码 kind 控制范围
host:view menu 主播列表、主播资料
host:update button 编辑主播资料
host:status button 主播状态调整
agency:view menu 公会列表、详情
agency:create button 新增公会
agency:update button 编辑公会
agency:status button 关闭公会、开关入会
bd:view menu BD 列表
bd:create button 新增 BD
bd:update button 编辑 BD
coin-seller:view menu 币商列表、币商余额
coin-seller:create button 新增币商
coin-seller:update button 启用或禁用币商
coin-seller:stock-credit button 币商进货、金币补偿
salary:view menu 薪资周期、薪资明细
salary:calculate button 计算薪资
salary:approve button 审批薪资
salary:post button 入账薪资
salary:void button 作废薪资
salary:adjust button 调整薪资项

角色预设

超级管理员

platform-admin

  • 拥有全部权限。
  • 能维护用户、角色、权限、菜单和所有业务模块。

运营负责人

ops-admin

  • 负责运营、团队、房间、资源、活动和游戏的日常管理。
  • 负责用户提现运营初审,不拥有用户提现财务终审权限。
  • 不包含后台设置、版本管理、财务负责人看板和三方汇率编辑/全局同步。

运营专员

operations-specialist

  • 可执行用户、团队结构、房间、资源和常规运营动作。
  • 可执行用户提现运营初审,不拥有用户提现财务终审权限。
  • 活动配置和游戏列表/自研游戏只读;可管理全站机器人和房内猜拳配置。

产品负责人

product-lead

  • 可管理 APP 配置、版本、房间、资源、活动和游戏。
  • 团队、支付、地区和 App 用户主资料按表格保持只读或限定动作。

产品专员

product-specialist

  • 负责资源配置;房间仅可管理机器人配置。
  • APP 配置、活动、游戏、支付和地区模块保持只读。

财务负责人

finance-lead

  • 只进入财务看板、充值对账、用户提现财务终审和房内猜拳订单;不参与运营初审。

财务专员

finance-specialist

  • 当前与财务负责人使用同一权限矩阵,负责用户提现财务终审且不参与运营初审;保留独立角色用于人员分工和后续数据范围配置。

固定岗位执行“同步权限”或显式 bootstrap 时按上述矩阵精确重建,清除历史跨模块绑定。历史 auditorreadonly 和用户自建角色不会被删除或重置。

前端落地规则

页面路由:

  • 路由必须配置菜单查看权限。
  • 没有菜单权限时跳转到用户有权限的第一个页面;不能固定跳到无权限页面。

菜单:

  • 左侧菜单只展示当前用户拥有 permission_code 的菜单。
  • 父菜单没有权限码时,只要存在可见子菜单即可展示。
  • 父菜单没有可见子菜单时不展示。

按钮:

  • 危险操作按钮没有权限时不展示。
  • 表格行内操作没有权限时不展示,必要时可以禁用但必须有明确状态。
  • 批量操作必须同时检查权限和选中项。
  • 导出按钮必须有独立导出权限。

搜索:

  • 搜索入口登录后可见。
  • 搜索结果按权限过滤。
  • 点击结果前仍由路由权限兜底。

后端落地规则

接口:

  • 除登录、刷新、健康检查外,所有接口必须先通过认证。
  • 每个写接口必须绑定按钮权限。
  • 每个读接口必须绑定菜单查看权限或更细读权限。
  • 批量、导出、重置密码、状态变更不能复用普通查看权限。

日志:

  • 创建、更新、删除、授权、状态变更、密码重置、导出、批量操作必须写操作日志。
  • 操作日志需要记录操作者、资源、动作、结果、详情、IP、路径。

权限变更:

  • 角色权限保存后必须记录操作日志。
  • 后续若要求立即生效,需要使相关用户 session 失效或提高 token version。

数据约束:

  • 权限 code 唯一。
  • 菜单 code 唯一。
  • 删除权限前必须确认没有角色绑定、没有菜单引用。
  • 删除菜单前必须确认没有子菜单,或明确采用级联删除策略。
  • 删除角色前必须确认没有用户绑定,或要求先解绑。

需要补齐的接口

权限定义

方法 路径 权限
GET /api/v1/permissions permission:view
POST /api/v1/permissions permission:create
PATCH /api/v1/permissions/:id permission:update
DELETE /api/v1/permissions/:id permission:delete
POST /api/v1/permissions/sync permission:sync

菜单管理

方法 路径 权限
GET /api/v1/system/menus menu:view
POST /api/v1/system/menus menu:create
PATCH /api/v1/system/menus/:id menu:update
DELETE /api/v1/system/menus/:id menu:delete
PATCH /api/v1/system/menus/:id/visible menu:visible
PUT /api/v1/system/menus/sort menu:sort

说明:

  • GET /api/v1/navigation/menus 保留为当前用户菜单接口,只返回当前用户可见菜单。
  • GET /api/v1/system/menus 是后台菜单维护接口,返回全量菜单树。

角色权限

方法 路径 权限
GET /api/v1/roles role:view
POST /api/v1/roles role:create
PATCH /api/v1/roles/:id role:update
DELETE /api/v1/roles/:id role:delete
PUT /api/v1/roles/:id/permissions role:permission

前端页面规划

角色配置页

功能:

  • 角色列表。
  • 新增角色。
  • 编辑角色。
  • 删除角色。
  • 打开授权抽屉。
  • 按模块、菜单、按钮分组勾选权限。

按钮权限:

  • 新增角色:role:create
  • 编辑角色:role:update
  • 删除角色:role:delete
  • 保存授权:role:permission

菜单权限页

功能:

  • 菜单树维护。
  • 菜单绑定权限码。
  • 菜单排序。
  • 菜单显隐。
  • 权限定义列表。
  • 权限同步。

按钮权限:

  • 新增菜单:menu:create
  • 编辑菜单:menu:update
  • 删除菜单:menu:delete
  • 排序:menu:sort
  • 显隐:menu:visible
  • 新增权限:permission:create
  • 编辑权限:permission:update
  • 删除权限:permission:delete
  • 同步权限:permission:sync

用户管理页

功能:

  • 用户列表。
  • 新增后台用户。
  • 编辑后台用户。
  • 绑定角色。
  • 启用、停用、锁定、解锁。
  • 重置密码。
  • 导出。

按钮权限:

  • 新增用户:user:create
  • 编辑用户:user:update
  • 状态操作:user:status
  • 重置密码:user:reset-password
  • 导出:user:export

验收标准

  • 无权限用户看不到对应菜单。
  • 直接访问无权限路由会被拦截。
  • 无按钮权限用户看不到对应操作按钮。
  • 直接调用无权限接口返回 403。
  • 角色授权保存后,用户重新登录或 refresh 后权限生效。
  • 创建、更新、删除、授权、导出、批量和状态类操作都有操作日志。
  • 全局搜索结果按当前用户权限过滤。
  • platform-admin 拥有所有权限。
  • 六个岗位角色的权限与 093_role_permission_matrix.sql 及后端默认矩阵完全一致。
  • 游戏列表、自研游戏、全站机器人、房内猜拳配置和房内猜拳订单互不借用查看或更新权限。
  • 支付账单导出/刷新、支付方式更新/同步、汇率编辑/同步互不借用列表查看权限。

维护规则

  1. 新增页面时先定义独立的 *:view,再按真实副作用拆按钮权限。
  2. 不允许为了复用一个 Handler把相邻菜单重新绑定到同一个宽权限。
  3. 固定岗位矩阵变更必须同时更新默认种子、版本化迁移和矩阵一致性测试。
  4. 旧权限码只能作为自定义历史角色的兼容入口,不能重新分配给七类固定岗位。