Skip to content

RBAC 数据模型

表结构说明。日常入口见 RBAC 文档,同步见同步规范,鉴权算法见算法说明

老系统继续写 users / menu.qx;beta 建新表,lims:rbac-sync 只读镜像。第一版不要求 legacy 双写,也不停 init_qx_list() 动态加列。


表名

统一 rbac_ 前缀,与 legacy 表区分。Model 放 App\Models\Rbac\*

新表来源
rbac_permissionsqx_list 树 / qx.php / users
rbac_rolesusers WHERE group='0'
rbac_role_permissions组行 qx=1 的列
rbac_user_roles用户 group 里的 |组名|
rbac_user_permission_snapshots快照 users.{qx}
rbac_menu_permissions解析 menu.qx
rbac_sync_runs同步审计
rbac_audit_logs权限操作记录;V1 sync 不写,beta 改权限起写入

permissions.code = qx_list.qx = users 列名,不做二次映射。std_code 为预留的标准编码,与 code 指向同一权限点。


rbac_permissions

权限目录与权限点共用一张父子表,对应 legacy qx_list 树形结构。

类型说明
idbigint PK
parent_idbigint nullable FK→ permissions.id;顶级目录为 NULL
node_typevarchar(16)category / permission
codevarchar(64) nullable权限点 = users 列名;目录节点为 NULL
std_codevarchar(128) nullable标准编码(如 site:station.manage);第一版可空,见下文
namevarchar(128)目录名或权限显示名
legacy_qx_list_idint nullable对应 qx_list.id
sortint default 0
is_activetinyint(1)业务是否启用该权限;0=废弃功能,但快照仍同步以保证完整镜像
is_systemtinyint(1) default 0admin/audit_test/user_manage 等
sourcevarchar(32) default qx_listqx_list / php_catalog / users_column / manual
source_filevarchar(255) nullable例如 user_manage/qx.phpgx_file/{dw}_qx.php
is_catalog_missingtinyint(1) default 01=users 有列但目录无定义
notevarchar(255) nullable
created_at / updated_attimestamp

索引:(code) unique;(std_code) unique;(parent_id, sort)(node_type, is_active)(legacy_qx_list_id)

约束:

  • node_type='category'code 为 NULL,不参与鉴权。
  • node_type='permission'code 必填且唯一。
  • node_type='permission'std_code 可空;非空则全局唯一(MySQL 允许多行 NULL)。
  • role_permissionsuser_permission_snapshotsmenu_permissions 只关联 node_type='permission' 的行。

is_active 字段说明

  • 含义:标识该权限是否在业务中启用(1=启用,0=废弃)
  • 同步规则:快照同步(P5)不过滤 is_active,所有权限(包括 inactive)都写入 user_permission_snapshots
  • 设计原则:快照应该是 Legacy users.{qx} 列的完整镜像,与业务是否使用该权限无关
  • 使用场景
    • ✅ 同步层:同步所有权限,保证数据完整性
    • ✅ 业务层:可根据 is_active 决定是否在 UI 中显示该权限选项
    • ✅ 鉴权层:可选择只检查 is_active=1 的权限(第一版不实现)

示例

  • Legacy 有 175 个权限列,其中 73 个已废弃(对应旧功能模块)
  • P1 同步:175 个都写入 rbac_permissions,废弃的标记 is_active=0
  • P5 同步:175 个权限全部写入快照(含 inactive)
  • VR3 验证:验证 175 个权限的快照与 Legacy 一致性 ✅

std_code(预留)

说明
含义同一权限点的「标准名」,建议形态 模块:功能:操作(如 huayan:report:export
codecode 仍是 legacy 主键(users 列、menu.qx);std_code 不替代 code
第一版 sync不填,保持 NULL
第一版鉴权has() 仅按 code 解析;不读 std_code
后期启用has('site:station.manage') 可先查 std_code 再落到同一 permission_id;关联表仍只绑 permission_id
多别名若需多个别名,再增 permission_aliases 表;单列 std_code 只保留一个标准名

rbac_roles

对应 users.group='0' 的组行。

类型说明
idbigint PK
legacy_user_idint unique组行 users.id
fzx_idint分中心
codevarchar(64)= 组 userid(可能是中文,如"主任")
std_codevarchar(64) nullable标准角色代码(英文,API/URL 使用,如"director");第一版为 NULL
namevarchar(128)
sortint default 0对应 px
is_activetinyint(1)对应 deled
created_at / updated_attimestamp

索引:(fzx_id, code) unique;(std_code) unique

说明

  • code:保持 Legacy 原始标识(可能是中文),用于与 users.group 字段匹配
  • std_code:预留的英文标识,用于 API/URL(第一版不填充,后期手动配置)
  • 示例:code='主任', std_code='director', name='主任'

rbac_role_permissions

类型说明
role_idbigint FK
permission_idbigint FK

PK:(role_id, permission_id)。sync 时组行 qx=1 的列写入本表。


rbac_user_roles

类型说明
user_idintusers.id
role_idbigint FK
assigned_attimestamp

PK:(user_id, role_id);索引 (role_id)


rbac_user_permission_snapshots

Legacy 最终权限在 users.{qx} 宽表列。sync 以宽表快照为准。

类型说明
user_idintusers.id
permission_idbigint FK
has_permissiontinyint(1)= users.{code} == '1'
same_as_role_permissionstinyint(1) nullable与组 union 是否一致,仅 verify 审计
synced_attimestamp

PK:(user_id, permission_id)
索引:(user_id, has_permission)(permission_id)

P5 规则(非 admin):

role_union(code) = EXISTS(role_permissions[role, code] for role in user_roles)
snapshot(code)   = users.{code} == '1'
→ upsert user_permission_snapshots(..., has_permission=snapshot, same_as_role_permissions=(snapshot==role_union))

admin 用户不写 user_permission_snapshots,运行时当超管。


rbac_menu_permissions

menu.qx 解析,不复制 menu 树。

类型说明
idbigint PK
legacy_menu_idintmenu.id
permission_idbigint nullable FK
tokenvarchar(32) nullableadmin/display/hide/empty
modifiervarchar(32) default require_anyrequire_any / deny_if_user_has / allow_all 等
sortint default 0CSV 顺序

索引:(legacy_menu_id)(permission_id)


rbac_sync_runs

类型说明
idbigint PK
started_at / finished_attimestamp
fzx_idint nullable
statusvarchar(16)running/success/failed
report_pathvarchar(255) nullable报告文件路径
error_messagetext nullable

rbac_audit_logs

权限 grant/revoke、角色分配、菜单规则变更等操作记录。与 rbac_sync_runs(只记录 sync 任务)分开。

类型说明
idbigint PK
actor_user_idint操作人
actor_useridvarchar(64) nullable操作人登录名
fzx_idint nullable分中心
target_typevarchar(32)user / role / permission / menu_permission / user_role / role_permission
target_idbigint nullable
subject_user_idint nullable被改权限的用户
role_idbigint nullable FK
permission_idbigint nullable FK
actionvarchar(32)grant / revoke / assign_role / remove_role / update_menu_rule 等
before_snapshottext nullable变更前
after_snapshottext nullable变更后
ipvarchar(45) nullable
created_attimestamp

索引:(actor_user_id)(subject_user_id)(target_type, target_id)(created_at)

写入:V1 sync 不写;legacy 保存仍用 other_log;beta 权限管理或切主后改 RBAC 必写。实现见 RbacAuditLogger(规划在 Foundation/RbacServices/Rbac)。


有效权限查询

sql
SELECT
    ups.user_id,
    p.code AS permission_code,
    ups.has_permission
FROM rbac_user_permission_snapshots ups
INNER JOIN permissions p ON p.id = ups.permission_id
WHERE p.is_active = 1;

读路径:超管短路 → 查 user_permission_snapshots → 无行 deny 并打日志。不 silent fallback Session 宽表。


menu.qxmenu_permissions
token=empty, modifier=allow_all
admintoken=admin, modifier=require_super_admin
!audit_testpermission=audit_test, modifier=deny_if_user_has
display / 隐藏token=display_hidden, modifier=legacy_hide(beta 默认不出)
普通 codepermission_id FK, modifier=require_any

菜单数据仍读 legacy menu;可见性读 menu_permissions + canViewMenu()


配置

变量默认说明
RBAC_ENFORCEfalse路由鉴权
RBAC_FALLBACK_LEGACY_SESSIONfalse仅本地对比,生产勿开
RBAC_CACHE_TTL_MINUTES10user_permission_snapshots 缓存
RBAC_SYNC_ON_DEPLOYfalse部署时可选自动 sync