front/docs/数据权限设计.md
zzh 2063621daf feat: 新增财务模块并优化组织管理、角色权限与我的订单
- 新增财务菜单与应收应付、充值记录、账户流水页面及路由

- 组织管理改为左右分栏,优化左侧树层级展示与选中交互

- 角色权限分配改为列表形式,支持各级菜单独立勾选

- 我的订单工具栏按钮样式与独立 loading 交互优化

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-04 12:15:14 +08:00

40 KiB
Raw Blame History

多维度组合数据权限设计方案 PRD

文档基础信息

项目 内容
文档名称 多维度交集式数据权限标准方案
适用系统 OMS 业务系统 + RBAC 管理端
关联文档 rbac系统设计-060801.md、oms系统设计-050801.md
权限架构 身份认证 → 功能权限(RBAC PermissionCode) → 数据权限(本方案),三层解耦
版本 V1.2
设计目标 在现有 RBAC 功能权限之上,为内部用户补齐多维数据过滤;与客户门户 CustomerId 硬隔离 并存、互不替代

导读:与 RBAC / OMS 的分工

三层权限模型

┌─────────────────────────────────────────────────────────────┐
│  身份认证(Authentication)                                    │
│  JWT:sub(GUID) + mapId(INT) + loginType(0内部/1客户)         │
│  详见 rbac §4                                                  │
├─────────────────────────────────────────────────────────────┤
│  功能权限(Authorization · 能做什么)                          │
│  用户角色 → role_permission → PermissionCode 并集 P            │
│  控制:菜单、按钮、API 是否可调用                                │
│  详见 rbac §5                                                  │
├─────────────────────────────────────────────────────────────┤
│  数据权限(Data Scope · 能看到哪些行)  ← 本文                 │
│  五维交集过滤,仅后端注入查询条件                                │
│  控制:列表/详情/导出/统计 返回的数据行范围                       │
└─────────────────────────────────────────────────────────────┘

关键原则:

  1. 有 Track.Orders.Query 功能权限,不代表能看全部订单;还须通过数据权限过滤。
  2. 数据权限不能替代功能权限;二者 AND 关系:先鉴权码、再滤数据。
  3. 客户门户(loginType=1)不走本文五维模型,走 OMS 既有 CustomerId 硬隔离(见 oms §4.4.0、OmsSessionHelper)。
  4. 内部用户(loginType=0) 才启用本文多维数据权限;超管白名单豁免。

双登录主体与数据隔离策略

主体 JWT loginType 数据隔离机制 配置入口
客户 / 子客户 1 CustomerId = effectiveCustomerId(会话解析,不可绕过) 无需数据权限配置;子客户功能范围由 RBAC 专属角色 CustomerSub_{userId} 控制
内部用户 0 本文五维交集 + 可选 CustomerId 等业务维度 RBAC 管理端「数据权限」Tab / 权限模板
超级管理员 0 角色 Code=Admin → 跳过全部数据维度 内置,不可关闭

双 ID 对齐(必须与 RBAC 一致)

标识 类型 数据权限表 / 业务表用法
user.Id CHAR(36) GUID 数据权限配置表 外键 UserId;组织权限 OrganizationId
user.userid INT 自增 JWT Claim mapId;OMS 审计字段 CreateUserId / UpdateUserId
organization.Id CHAR(36) GUID 组织维度过滤;禁止使用自增 bigint 作为 org_id
t_customer.Id BIGINT OMS 业务 CustomerId;销售负责范围过滤时的业务键

修正(相对 V1.0):V1.0 中 user_id bigint、org_id bigint 与现网 RBAC 不一致,统一改为 GUID;OMS 侧负责人仍用 CreateUserId(INT mapId)。


一、需求概述

1.1 业务痛点

原有仅依靠 user.OrganizationId(单组织归属)+ 管理员无过滤(ResolveListCustomerIdAsync 返回 null)存在以下问题:

  1. 同部门不同岗位(销售 vs 客服 vs 财务)数据可见范围无法区分;
  2. 产品、运营、总部职能岗需要跨分公司查看指定产品线/区域数据;
  3. 营收、客户隐私、成本等敏感字段无法独立管控与脱敏;
  4. 不支持时间、金额、单据状态等岗位级动态范围限制;
  5. 临时授权无时效回收;内部用户查单/查客无审计追溯;
  6. 客户门户已有 CustomerId 隔离,但运营后台仍「登录即全量」,与合规要求不符。

1.2 核心设计原则

  1. 功能权限与数据权限解耦(见导读三层模型)。
  2. 多维度取交集(内部用户):
    可见数据 = 组织过滤 ∩ 数据范围 ∩ 业务标签 ∩ 密级 ∩ 自定义条件
    
  3. 密级最高优先级:无密级权限的行直接过滤;有权限但字段级敏感则脱敏展示(仍返回行)。
  4. 最小权限原则:新建内部用户默认无扩展数据权限(仅组织默认范围,见 §2.1.4);须管理员分配或套用模板。
  5. 超级管理员白名单:角色 Admin 跳过五维过滤。
  6. 后端唯一可信:全部过滤在 Service/Repository 层注入;前端不做数据拦截。
  7. 分模块接入:订单、客户、充值、渠道配置等按 DataResourceCode 注册,统一走 IDataScopeApplier。

1.3 五大权限控制维度(仅内部用户)

维度 回答的问题 典型 OMS 落点
1. 组织 哪个分公司/部门的数据? 订单扩展字段 OrganizationId;客户列表按销售组织
2. 数据范围 本人 / 本组 / 本部门 / 组织树 / 全局? CreateUserId、t_customer.Salesman
3. 业务标签 哪条产品线/区域/KPI 分区? 销售产品、KPI 分区、客户分组 CustomerGroup
4. 数据密级 能否看机密/绝密字段? 费用明细、成本、利润、客户手机号
5. 自定义过滤 时间/金额/状态等附加条件? 本年度订单、金额>1万、排除作废

二、详细功能需求

2.1 维度 1:组织数据权限

2.1.1 组织架构模型(对齐 RBAC organization)

复用 RBAC 组织树,不另建组织主数据:

公司 → 事业部 → 分公司 → 部门 → 小组
RBAC 字段 说明
organization.Id GUID,数据权限过滤键
organization.ParentId 树形父节点
organization.Type OrganizationType:1/2/3(与 RBAC 枚举一致)
user.OrganizationId 用户主归属组织,作默认数据范围起点

2.1.2 组织权限范围枚举

编码 名称 规则说明
1 仅本级组织 仅 OrganizationId = 授权组织,不含下级
2 本级 + 所有下级 授权组织及其子树(管理岗默认)

2.1.3 业务规则

  1. 平级组织默认互相隔离;
  2. 支持一人多组织授权(多条 user_org_perm);
  3. 支持跨组织白名单(总部财务、审计勾选多个分公司);
  4. 用户主归属 user.OrganizationId 在未单独配置时,作为默认组织范围(本级+下级)。

2.1.4 与 OMS 业务表映射

业务实体 组织字段策略 说明
t_order 新增 OrganizationId CHAR(36) NULL 创建时取自客户归属组织或操作人主组织;历史数据可批量回填
t_customer 新增 OrganizationId CHAR(36) NULL 客户归属销售组织;与 Salesman 联动维护
t_recharge_record 继承 CustomerId → t_customer.OrganizationId 查询时 JOIN,不必冗余
渠道/系统主数据 默认不受组织维限制 通过功能权限 + 密级控制;若需按组织隔离再扩展

2.2 维度 2:角色数据范围

2.2.1 数据范围枚举

编码 名称 SQL 语义(以订单为例)
1 个人级 CreateUserId = 当前 mapId 或 t_customer.Salesman = 当前用户账号
2 小组级 同 user.OrganizationId 且组织 Type=小组 的全体 mapId
3 部门级 同部门组织子树内所有用户的 mapId
4 组织树级 以授权组织为根的子树内全部数据
5 全局级 不追加负责人过滤(仍受组织/业务/密级/自定义约束)

2.2.2 与 RBAC 角色的关系

配置方式 优先级 说明
角色级默认 role_data_scope 低 角色绑定数据范围,用户继承其所有角色的最大值(取最宽)
用户级覆盖 user_data_scope 高 显式配置则覆盖角色默认

示例:用户同时有「销售专员」(个人级) 和「销售主管」(部门级) 两角色 → 有效范围为 部门级(取 max)。

2.2.3 OMS 业务配套字段

字段 表 用途
CreateUserId 各 OMS 业务表 INT,= user.userid;个人级过滤
Salesman t_customer VARCHAR,可与 user.Account 对应;销售看自己的客户
CustomerService t_customer 客服负责范围(可选启用)
CustomerId t_order 等 先按客户归属,再按客户负责人收窄

内部用户查订单推荐链路:

t_order
  → CustomerId → t_customer(Salesman / OrganizationId)
  → CreateUserId(下单操作人)
按 data_scope 选用 CreateUserId 或 Salesman 或组织子树

2.3 维度 3:业务维度权限(跨组织)

2.3.1 业务分类类型(OMS 落地)

biz_type 编码 名称 OMS 数据源
product_line 产品线 t_sales_product / 产品分类
kpi_area KPI 分区 t_kpi_area
customer_group 客户分层 t_customer.CustomerGroup(0 普通,1~5 VIP)
warehouse 仓库 t_warehouse_address.Id
region 区域 字典或 KPI 分区上级(可扩展)

2.3.2 控制规则

  1. 独立于组织架构,支持多选;OR 语义:命中任一已授权标签即可;
  2. 与组织维度 AND:须同时满足组织范围 且 业务标签;
  3. 用户未配置任何业务标签 = 不限制业务标签(与 V1.0「无标签=无权限」不同,避免过度收紧;若需强制可 per-module 配置 RequireBizTag=true);
  4. 业务表映射:
表 过滤字段
t_order ProductCode → 产品 → 产品线;ConsigneeCountry + KPI 分区
t_customer CustomerGroup
渠道配置 直接按产品/分区 Id

2.4 维度 4:数据密级权限(行级 + 字段级)

2.4.1 密级分级

编码 名称 典型数据
1 公开级 运单号、状态、路由
2 内部级 应收费用、客户名称
3 机密级 应付/成本、毛利、完整地址
4 绝密级 手机号、身份证、银行信息、完整利润

2.4.2 两级控制

级别 行为
行级 secret_level 高于用户授权 → 整行不返回
字段级 行可见但字段密级超限 → 脱敏(如 138****1234),接口仍 200

2.4.3 业务表字段

表 策略
t_order 表级默认密级 2;t_order_fee 应付行密级 3
t_customer 表级密级 3;Phone/Email 字段密级 4
t_recharge_record 密级 3(含金额)

新增通用字段(按需,非全表强制):

  • SecretLevel TINYINT NOT NULL DEFAULT 2

2.5 维度 5:自定义行过滤条件

2.5.1 支持的条件类型

类型 示例 适用表
时间 本年度、近 3 个月、自定义区间 t_order.CreateTime
数值 应收合计 > 10000 t_order_fee 聚合
枚举 OrderStatus IN (...) t_order
渠道 指定 ProductCode / ChannelCode t_order

2.5.2 安全实现

  1. 可视化表单 → AST → SqlSugar 表达式,禁止管理员输入原生 SQL;
  2. 按 DataResourceCode(如 Order、Customer、Recharge)区分规则;
  3. 条件仅 AND 追加到交集结果,不改变业务接口原有筛选参数语义。

2.6 特殊权限:临时数据权限

项 说明
场景 审计、跨部门对账、临时顶岗
配置 关联用户 GUID、全套五维副本、生效/过期时间
存储 各 user_*_perm 表 ExpireTime 非空;或独立 user_data_perm_grant 快照
生效 EffectiveTime <= NOW() < ExpireTime 的记录参与计算;过期自动失效
审计 标记 IsTemporary=1;访问日志单独索引

2.7 权限模板

预设岗位模板,一键写入角色或用户的数据权限配置:

模板 组织 数据范围 业务 密级
普通销售 主归属、仅本级 个人级 指定产品线 1、2
销售主管 本级+下级 部门级 全部产品线 1、2、3
分公司经理 本级+下级 组织树级 全部 1、2、3
总部产品经理 多组织白名单 全局级 单一产品线 1、2
财务专员 本级+下级 组织树级 全部 含 3、4(字段脱敏策略另配)
客服专员 本级 个人级 — 1、2(客户手机号脱敏)

支持自定义模板 CRUD;模板可绑定 RBAC 角色 Code,新用户分配角色时自动继承。


三、后端核心权限计算逻辑

3.1 通用计算公式

记当前内部用户有效配置(已合并多角色、已过滤过期临时授权):

  • OrgFilter:组织维度 SQL 条件
  • ScopeFilter:数据范围条件
  • BizFilter:业务标签条件(空配置 = 恒真)
  • SecretFilter:密级条件
  • CustomFilter:自定义条件

最终查询条件:

WHERE IsDeleted = 0
  AND (Admin ? TRUE : (
        OrgFilter
    AND ScopeFilter
    AND BizFilter
    AND SecretFilter
    AND CustomFilter
  ))
  AND <业务接口原有筛选>

伪代码:

async Task<Expression<Func<T, bool>>> BuildDataScopeAsync<T>(
    DataResourceCode resource,
    ICurrentUser user)
{
    if (user.IsInRole("Admin")) return _ => true;
    if (OmsSessionHelper.IsCustomerLogin(user))
        throw new InvalidOperationException("客户门户走 CustomerId 隔离");

    var ctx = await _dataPermCache.GetOrLoadAsync(user.Id); // GUID
    var parts = new List<Expression<Func<T, bool>>>();

    parts.Add(BuildOrgFilter<T>(ctx, resource));
    parts.Add(BuildScopeFilter<T>(ctx, user.GetId<int>(), resource));
    parts.Add(BuildBizFilter<T>(ctx, resource));
    parts.Add(BuildSecretFilter<T>(ctx));
    parts.Add(BuildCustomFilter<T>(ctx, resource));

    return parts.Aggregate((a, b) => a.And(b));
}

3.2 超级管理员豁免

满足任一条件跳过五维过滤:

  1. 用户角色包含 Code = Admin(RBAC 种子超管);
  2. 或显式 user.IsSuperAdmin = 1(扩展字段,可选)。

仍受 功能权限码 约束(若无 Track.Orders.Query 仍不可调用接口)。

3.3 与客户门户的并存规则

同一套路由 /admin/order/*(服务内 /order/*),不按门户拆 URL;在 OrderService 入口按 loginType 分支:

loginType 隔离方式
1 客户 OmsSessionHelper → CustomerId = effectiveCustomerId
0 内部 + Admin 不加五维
0 内部 + 非 Admin DataScopeApplier 五维交集
flowchart TD
    A["POST /admin/order/list"] --> B{loginType?}
    B -->|1 客户| C[CustomerId 硬隔离]
    B -->|0 内部| D{Admin?}
    D -->|是| E[无五维过滤]
    D -->|否| F[DataScopeApplier]
    C --> G[查询]
    E --> G
    F --> G

3.4 演算示例

用户:华南分公司销售经理(非 Admin)

维度 配置
组织 华南分公司,本级+下级
数据范围 组织树级
业务 线上零售产品线
密级 1、2、3
自定义 2026 年、已付款

订单列表 SQL 语义:

WHERE t_order.IsDeleted = 0
  AND t_order.OrganizationId IN (华南分公司子树 GUID 列表)
  AND t_order.ProductCode IN (线上零售产品 Code 列表)
  AND t_order.SecretLevel <= 3
  AND YEAR(t_order.CreateTime) = 2026
  AND t_order.OrderStatus = 'pendingPayment' -- 已付款态按业务枚举调整
  -- 不含 CustomerId 全量;内部运营后台不按单客户隔离

四、数据库设计

RBAC 库(EF)与 OMS 库(SqlSugar)可同实例不同表;数据权限配置表建议放 RBAC 库,与 user/role/organization 同库 FK。

4.1 用户组织权限 user_org_perm

字段 类型 说明
Id CHAR(36) PK
UserId CHAR(36) FK → user.Id
OrganizationId CHAR(36) FK → organization.Id
OrgScope TINYINT 1 仅本级 / 2 本级+下级
EffectiveTime DATETIME 生效时间,默认创建时
ExpireTime DATETIME NULL=永久
IsTemporary TINYINT 0/1
CreateTime DATETIME

4.2 角色 / 用户数据范围

role_data_scope

字段 类型 说明
Id CHAR(36) PK
RoleId CHAR(36) FK → role.Id
DataScope TINYINT 1~5
DataResourceCode VARCHAR(32) 可选,空=全局默认

user_data_scope(用户级覆盖)

字段 类型 说明
Id CHAR(36) PK
UserId CHAR(36) FK → user.Id
DataScope TINYINT 1~5
DataResourceCode VARCHAR(32) 可选

4.3 用户业务维度 user_biz_perm

字段 类型 说明
Id CHAR(36) PK
UserId CHAR(36)
BizType VARCHAR(32) product_line / kpi_area / customer_group / warehouse
BizId VARCHAR(64) 业务主键(兼容 GUID 与 INT 字符串)
ExpireTime DATETIME 可空

4.4 用户密级 user_secret_perm

字段 类型 说明
Id CHAR(36) PK
UserId CHAR(36)
SecretLevel TINYINT 1~4
DataResourceCode VARCHAR(32) 可选,按模块细分

4.5 用户自定义过滤 user_filter_rule

字段 类型 说明
Id CHAR(36) PK
UserId CHAR(36)
DataResourceCode VARCHAR(32) Order / Customer / Recharge
FilterContent JSON 前端配置 AST
FilterHash VARCHAR(64) 内容哈希,便于缓存失效
CreateTime DATETIME

不再存储 filter_snippet 原生 SQL 文本;运行时由 AST 生成表达式,避免 SQL 注入与方言耦合。

4.6 权限模板 data_perm_template / data_perm_template_item

模板头 + 明细行(DimensionType + ItemContent JSON),支持绑定 RoleCode。完整 DDL 见 §十三 与 sql/install_data_permission.sql。

角色级五维表(与用户对偶,供模板套用与角色继承):

  • role_org_perm · role_data_scope · role_biz_perm · role_secret_perm · role_filter_rule

4.7 数据权限审计 data_perm_access_log

字段 说明
UserId、DataResourceCode、ApiPath 谁访问了什么
AppliedScopeJson 本次生效的五维快照
QueryTime、RowCount 性能与合规

4.8 OMS 业务表扩展(分期)

阶段 表 新增字段
P1 t_customer OrganizationId CHAR(36)
P1 t_order OrganizationId CHAR(36)、SecretLevel TINYINT DEFAULT 2
P2 t_order_fee 应付行 SecretLevel、字段级脱敏配置
P2 t_recharge_record SecretLevel

不强制全表统一 biz_type/biz_id/owner_user_id;改用 OMS 已有字段 + JOIN 映射(见 §2.3、§2.2.3)。


五、接口与执行流程

5.1 服务组件

组件 职责
IDataPermissionRepository 读配置表
IDataScopeContextFactory 合并角色+用户配置 → DataScopeContext
IDataScopeApplier 按 DataResourceCode 注入 SqlSugar Queryable
IFieldMaskingService 密级字段脱敏
DataPermissionCache Redis:data_perm:{userGuid},TTL 30min

5.2 请求链路

  1. JWT 校验 → 解析 sub(GUID)、mapId、loginType;
  2. [Authorize(Permission = "...")] 功能权限校验(RBAC 完善后启用);
  3. loginType=1 → OmsSessionHelper CustomerId 分支;
  4. loginType=0 → 加载 DataScopeContext → Applier 注入条件;
  5. 查询结果 → IFieldMaskingService 按密级脱敏;
  6. 写 data_perm_access_log(异步,可采样)。

5.3 权限变更与缓存

事件 动作
用户数据权限 CRUD 删除 data_perm:{userId}
用户角色变更 同上
组织树移动 批量失效该组织下用户缓存
模板绑定角色更新 失效该角色所有用户

5.4 管理端 API(建议前缀 /rbac/data-perm/*)

方法 路径 说明
GET /rbac/data-perm/get-by-user 查询用户五维配置
PUT /rbac/data-perm/save-user 保存用户五维
GET /rbac/data-perm/template/list 模板列表
POST /rbac/data-perm/template/apply 模板套用到用户/角色
GET /rbac/data-perm/access-log 审计分页

权限码建议:Rbac.DataPerm.Query、Rbac.DataPerm.Update(在 PermissionDefinitionProvider 注册)。

5.5 登录响应扩展(可选)

GET /rbac/auth/get-current-user 增加只读摘要(不含 SQL):

{
  "dataScopeSummary": {
    "isAdmin": false,
    "orgNames": ["华南分公司"],
    "dataScope": 4,
    "secretLevels": [1, 2, 3]
  }
}

供前端展示「当前数据范围」提示,不可替代后端过滤。


六、分模块接入清单(OMS)

DataResourceCode 服务 主表 组织字段 范围字段 备注
Order OrderService t_order OrganizationId CreateUserId + Customer.Salesman 同 /admin/order/list,内部用户走 Applier
Customer CustomerService t_customer OrganizationId Salesman / CustomerService /customer/list 内部查询
Recharge RechargeService t_recharge_record via Customer CreateUserId 审核列表
ChannelProduct SalesProductService t_sales_product — 业务标签 product_line 配置类,密级偏低
Xhs Xhs*Service 各 t_xhs_* — CustomerId(已有) 内部用户走五维;客户走 Xhs CustomerId

客户门户模块(/admin/order/*、Xhs 客户侧):不接入五维 Applier,保持现有 OmsSessionHelper。


七、前端功能需求

7.1 用户数据权限编辑(/system/users 或 RBAC 用户详情)

  • Tab:组织 / 数据范围 / 业务标签 / 密级 / 自定义过滤;
  • 组织树勾选:复用 GET /rbac/organization/get-tree;
  • 权限模板一键填充;
  • 临时权限:EffectiveTime + ExpireTime。

7.2 权限模板管理

  • CRUD + 绑定 RoleCode;
  • 预览「有效 SQL 语义」只读说明(不给 SQL 编辑)。

7.3 权限审计日志

  • TablePro:用户、模块、时间、AppliedScopeJson 展开;
  • 导出 Excel。

7.4 密级与脱敏配置

  • 维护 DataResourceCode + 字段名 → SecretLevel 映射表;
  • 与接口响应 DTO 字段对齐。

7.5 前端约束

  • hasPermission() 恢复真实校验(rbac §9.4)后,按钮与数据范围提示分离;
  • 禁止前端按组织/密级过滤列表数据。

八、非功能性需求

类别 要求
安全 后端过滤;AST 白名单运算符;字段脱敏;临时权限强制过期
性能 Redis 缓存 Context;(OrganizationId, CreateTime)、(CustomerId) 索引
扩展 新模块注册 DataResourceCode + Applier 策略类
易用 模板 + 角色继承;组织树可视化
审计 权限变更日志 + 访问采样日志

九、典型岗位配置示例

示例 1:普通销售(内部)

  • 组织:主归属销售部,仅本级
  • 数据范围:个人级(Salesman = 本人账号)
  • 业务:负责产品线
  • 密级:1、2
  • 接口:Track.Orders.Query + 五维过滤

示例 2:分公司销售经理

  • 组织:本分公司,本级+下级
  • 数据范围:组织树级
  • 业务:全部产品线
  • 密级:1、2、3
  • 自定义:本年度

示例 3:总部产品经理(跨组织)

  • 组织:多分公司白名单
  • 数据范围:全局级
  • 业务:单一产品线
  • 密级:1、2

示例 4:客户主账号(门户)

  • 不配置五维
  • loginType=1,CustomerId 硬隔离
  • 功能权限:角色 Customer + 分配的 PermissionCode

示例 5:子客户

  • 不配置五维
  • 订单归属主客户 CustomerId(推荐策略,oms §1.4)
  • 功能权限:角色 CustomerSub_{userId} ⊆ 主客户权限

示例 6:超级管理员

  • 角色 Admin:跳过五维
  • 仍配置功能权限码(默认全开)

十、实施分期

阶段 内容 依赖
P0 OrderService 同路由按 loginType 分支;内部非 Admin 接 DataScopeApplier(替换管理员无过滤) 无路由变更
P1 建 RBAC 数据权限表;OrganizationId 落库客户/订单;组织+数据范围两维;Order/Customer 接入 RBAC 迁移
P2 业务标签、密级、字段脱敏 产品/KPI 主数据
P3 自定义过滤 AST、临时权限、审计页 P1 稳定
P4 权限模板与角色联动;[Authorize(Permission)] 全量启用 RBAC 包升级

十一、与现有实现的差异对照

项 本文目标 当前 oms0414-back
客户门户隔离 CustomerId 强制 ✅ OmsSessionHelper 已实现
内部用户查订单 五维过滤 ⚠️ ResolveListCustomerIdAsync 管理员返回 null,无过滤
组织主数据 复用 RBAC organization ✅ 已有,未用于数据过滤
功能权限 PermissionCode + 数据权限 ⚠️ 细粒度 Permission 拦截待实现
用户 ID GUID 配置 + INT 审计 ✅ 与 RBAC 一致

十二、交付说明

  1. 本文档与 rbac系统设计-060801.md、oms系统设计-050801.md 配套使用,冲突时以双登录主体分工(导读)为准;
  2. 建表 SQL 见 oms0414-back/sql/install_data_permission.sql、migrate_oms_data_permission_columns.sql;
  3. 新业务模块在 §六 注册 DataResourceCode 后接入 IDataScopeApplier;
  4. 客户门户 禁止 接入五维 Applier,继续用 CustomerId 隔离;
  5. V1.0 中「所有业务表统一五字段」改为 分期扩展 + 字段映射,降低 OMS 全表改造风险。

十三、表结构详设

13.1 ER 关系

erDiagram
  user ||--o{ user_org_perm : has
  user ||--o{ user_data_scope : has
  user ||--o{ user_biz_perm : has
  user ||--o{ user_secret_perm : has
  user ||--o{ user_filter_rule : has
  role ||--o{ role_org_perm : has
  role ||--o{ role_data_scope : has
  role ||--o{ role_biz_perm : has
  role ||--o{ role_secret_perm : has
  role ||--o{ role_filter_rule : has
  organization ||--o{ user_org_perm : scoped
  data_perm_template ||--o{ data_perm_template_item : contains
  data_resource ||--o{ data_perm_field_mask : masks

13.2 表清单

表名 库 说明
user_org_perm RBAC 用户组织权限
role_org_perm RBAC 角色组织权限
user_data_scope RBAC 用户数据范围(覆盖角色)
role_data_scope RBAC 角色数据范围
user_biz_perm RBAC 用户业务标签
role_biz_perm RBAC 角色业务标签
user_secret_perm RBAC 用户密级
role_secret_perm RBAC 角色密级
user_filter_rule RBAC 用户自定义过滤 AST
role_filter_rule RBAC 角色自定义过滤 AST
data_resource RBAC 模块注册(Order/Customer…)
data_perm_field_mask RBAC 字段脱敏规则
data_perm_template RBAC 权限模板头
data_perm_template_item RBAC 模板明细
data_perm_change_log RBAC 配置变更审计
data_perm_access_log RBAC 访问审计(采样)
t_customer.OrganizationId OMS P1 扩展
t_order.OrganizationId/SecretLevel OMS P1 扩展

13.3 有效权限合并规则(运行时唯一标准)

配置页(get-by-user)展示库表原值;运行时(get-effective / 列表过滤)按下表合并。二者不可混用。

维度 角色侧 用户直配 合并算法 空配置默认
组织 多角色 UNION UNION 到角色结果 展开子树后 OrganizationId IN (...) 无任一条时回退 user.OrganizationId(scope=2)
数据范围 多角色取 MAX 按资源覆盖角色结果 见 §14.1 步骤 5 无配置 → Personal(1)
业务标签 多角色 UNION UNION 同类型 bizId 并集;有过滤则 OR 命中 空=不限制
密级 UNION UNION SecretLevel IN (授权集合) 无配置 → [1,2](公开+内部)
自定义过滤 多规则 AND AND AST 逐条 AND 无规则 → 恒真

过期:运行时排除 EffectiveTime > NOW() 或 ExpireTime <= NOW() 的行。
Admin:角色 Code=Admin → 跳过五维,但仍走功能 PermissionCode。
客户:loginType=1 → 不算五维,走 CustomerId(与本文无关)。

13.4 枚举常量

OrgScope

值 名称
1 SelfOnly
2 SelfAndChildren

DataScope

值 名称 说明
1 Personal CreateUserId=mapId 或 Salesman=Account
2 Team 同小组组织下用户
3 Department 同部门子树
4 OrgTree 授权组织子树
5 Global 不追加负责人条件

BizType

值 OMS 映射
product_line t_sales_product 分类 / ProductCode 前缀
kpi_area t_kpi_area.Id
customer_group t_customer.CustomerGroup
warehouse t_warehouse_address.Id / t_order.WarehouseId
region 字典扩展

SecretLevel

值 名称
1 Public
2 Internal
3 Confidential
4 TopSecret

DataResourceCode(见 data_resource.Code)

Order · Customer · Recharge · ChannelProduct · Xhs

Filter AST 运算符(白名单)

eq · ne · in · notIn · gt · gte · lt · lte · between · like · isNull · isNotNull

Filter AST 示例

{
  "logic": "and",
  "conditions": [
    { "field": "CreateTime", "op": "between", "value": ["2026-01-01", "2026-12-31"] },
    { "field": "OrderStatus", "op": "in", "value": ["pendingPayment", "pendingShip"] },
    { "field": "DeclaredSum", "op": "gte", "value": 10000 }
  ]
}

模板 ItemContent 按 DimensionType

DimensionType JSON 结构
org { "organizationId": "guid", "orgScope": 2 }
data_scope { "dataScope": 3, "dataResourceCode": "Order" }
biz { "bizType": "product_line", "bizId": "US_AIR", "bizName": "美线空运" }
secret { "secretLevels": [1,2,3], "dataResourceCode": null }
filter { "dataResourceCode": "Order", "filterContent": { ...AST } }

十四、接口与核心逻辑详设

路由 /rbac/data-perm/*;分页 { total, items };写操作单事务、软删旧行+插新行。

14.0 产品决策(已确认)

# 决策 结论
1 订单路由 不分离;/admin/order/* 内按 loginType 分支
2 新员工默认 dataScope Personal(1)
3 改自己的数据权限 禁止(403)
4 模板批量套用 部分失败继续,返回 failures[]
5 access-log 自动写入 P1 不做;前端审计页已预留

14.0.1 前端页面(oms0414)

路由 组件 说明
/system/dataPerm/users views/system/dataPerm/users/index.vue 用户列表 + 五维配置抽屉
/system/dataPerm/templates views/system/dataPerm/templates/index.vue 模板 CRUD + 批量套用
/system/dataPerm/audit views/system/dataPerm/audit/index.vue 变更日志 / 访问日志 Tab

API 客户端:src/api/rbac/data-perm.ts(后端未就绪时会 404,页面已 catch)。


14.1 三个核心类(必须先实现)

类 职责
EffectiveScopeBuilder 角色+用户+默认 → DataScopeContext
DataScopeApplier Context → SqlSugar 条件(/order/list 等)
FilterAstValidator 校验/编译 filterContent
record DataScopeContext {
  bool IsAdmin;
  Guid UserId; int MapId; string Account;
  string DataResourceCode;
  IReadOnlySet<Guid> OrganizationIds;
  int DataScope;                                    // 1~5
  IReadOnlyList<int> ResolvedOwnerIds;              // Team/Dept 预解析 mapId
  IReadOnlyDictionary<string, string[]> BizFilters; // null=不限制
  IReadOnlySet<int> SecretLevels;
  IReadOnlyList<CompiledFilter> CustomFilters;
}

缓存:data_perm:ctx:{userId}:{resourceCode} TTL 30min;配置变更 DEL 该 user 全部 ctx。


14.2 运行时合并规则

维度 算法
组织 role_org_perm ∪ user_org_perm → OrgScope 展开子树 → IN;全无 → user.OrganizationId(scope=2)
数据范围 用户专码 > 用户全局 > 角色专码 MAX > 角色全局 MAX;全无 → Personal(1)
业务 并集;空=不限制
密级 并集;空 → [1,2]
自定义 全部 AND
过期 运行时排除;get-by-user 编辑页仍展示过期行并标 isExpired

get-by-user 仅 user_* 直配;get-effective-by-user 走 Builder 合并结果。


14.3 EffectiveScopeBuilder.BuildAsync

入参:userId, dataResourceCode(如 Order)

  1. 查 user,不存在 → 404
  2. 角色含 Admin → { IsAdmin=true }
  3. 组织:role∪user 行 → FilterEffective → 展开子树 → OrganizationIds
  4. 数据范围:用户专码/全局优先,否则角色 MAX,否则 1
  5. 业务:role∪user → 分组;空 → null
  6. 密级:并集;空 → [1,2]
  7. 过滤:role∪user 同 resource → Compile → AND
  8. dataScope∈{2,3} 时预解析 ResolvedOwnerIds;无 user.OrganizationId → 业务异常

14.4 DataScopeApplier(/admin/order/* 同路由)

在 OrderService 列表/详情/导出等读路径入口:

  1. loginType=1 → 仅 CustomerId(现有 OmsSessionHelper)
  2. loginType=0 + Admin → 不加五维
  3. loginType=0 + 非 Admin → BuildAsync(currentUser, "Order") 后:
    • OrganizationId IN ctx.OrganizationIds
    • SecretLevel IN ctx.SecretLevels
    • BizFilters 按注册表翻译
    • dataScope:Personal → CreateUserId=mapId OR Salesman=Account;Team/Dept → CreateUserId IN ResolvedOwnerIds;OrgTree/Global → 不加 Owner
    • CustomFilters AND
  4. DTO 映射阶段 FieldMaskingService 脱敏
  5. P1 不写 access-log

14.5 HTTP 共性

  • 鉴权:Bearer + PermissionCode
  • 可配置主体:内部用户;纯 Customer/CustomerSub → save 拒绝
  • save-user:targetUserId == 操作者 userId → 403「不能修改自己的数据权限」
  • 双库:RBAC EF + OMS SqlSugar(biz-options 读 OMS)

14.6 接口逐步逻辑

GET /meta — Rbac.DataPerm.Query

代码常量枚举 + data_resource 表 + 每 resource 的 filterableFields 字典;不读当前用户权限。

GET /biz-options — Query

bizType 必填。分支:product_line→t_sales_product;kpi_area→t_kpi_area;customer_group→0~5 常量;warehouse→t_warehouse_address。keyword 模糊分页。

GET /get-by-user — Query userId

查 user + 五张 user_*(IsDeleted=0,含过期);纯客户 → 400;JOIN 组织名;不调 Builder。

GET /get-effective-by-user — Query userId, dataResourceCode

BuildAsync → 组织名 → summaryText;Admin 短路。

PUT /save-user — Query userId

校验(组织启用、枚举、去重、AST、禁止 self-edit)→ 事务:软删旧 user_* → 插新 → change_log → 失效缓存 → 返回 get-by-user。

GET/PUT get-by-role / save-role

对称读写 role_*;save-role 后失效该角色所有 user 的 ctx 缓存。

模板 list/get/create/update/delete

create/update 校验 item JSON Schema;内置模板不可删、不可改 code。

POST /template/apply

加载模板 → PermBundle;foreach targetId:失败则 failures+=reason, continue(部分失败继续);replace/merge 规则:org/biz/secret Union,scope Max,filter 追加 AND;调内部 save;返回 { successCount, failures[] }。

field-mask/list|save

按 resource 全量覆盖脱敏规则。

change-log/list

配置变更只读分页(P1 必做)。

access-log/list

只读分页;P1 无自动写入,表结构预留。

POST /invalidate-cache

运维 DEL Redis ctx。

get-current-user 扩展

loginType=1 → null;Admin → summary;否则 Builder 仅取 summaryText + secretLevels。


14.7 路径速查

方法 路径 PermissionCode
GET /rbac/data-perm/meta Rbac.DataPerm.Query
GET /rbac/data-perm/biz-options Rbac.DataPerm.Query
GET /rbac/data-perm/get-by-user Rbac.DataPerm.Query
GET /rbac/data-perm/get-effective-by-user Rbac.DataPerm.Query
PUT /rbac/data-perm/save-user Rbac.DataPerm.Update
GET /rbac/data-perm/get-by-role Rbac.DataPerm.Query
PUT /rbac/data-perm/save-role Rbac.DataPerm.Update
GET /rbac/data-perm/template/list Rbac.DataPerm.Template
GET /rbac/data-perm/template/get Rbac.DataPerm.Template
POST /rbac/data-perm/template/create Rbac.DataPerm.Template
PUT /rbac/data-perm/template/update Rbac.DataPerm.Template
DELETE /rbac/data-perm/template/delete Rbac.DataPerm.Template
POST /rbac/data-perm/template/apply Rbac.DataPerm.Update
GET /rbac/data-perm/field-mask/list Rbac.DataPerm.Query
PUT /rbac/data-perm/field-mask/save Rbac.DataPerm.Update
GET /rbac/data-perm/change-log/list Rbac.DataPerm.Audit
GET /rbac/data-perm/access-log/list Rbac.DataPerm.Audit
POST /rbac/data-perm/invalidate-cache Rbac.DataPerm.Update

14.8 权限码

Rbac.DataPerm · .Query · .Update · .Template · .Audit

14.9 错误码补充

场景 消息
修改自己的数据权限 不能修改自己的数据权限
纯客户账号 save 客户账号不支持数据权限配置
template apply 单条失败 记入 failures[].reason,不中断批次

14.10 实施顺序

  1. EffectiveScopeBuilder + 单测
  2. meta / get-by-user / get-effective
  3. save-user / save-role + change-log
  4. Applier 接入 /order/list(同路由 loginType 分支)
  5. template / biz-options
  6. field-mask;(access-log 写入 Phase 2)

14.11 JSON 契约摘要

UserDataPermDto:userId、orgPerms[]、dataScopes[]、bizPerms[]、secretPerms[]、filterRules[](含 isExpired)。

SaveUserDataPermInput:同上五数组,全量覆盖;缺省数组=清空该维。

EffectiveDataScopeDto:isAdmin、organizationIds[]、dataScope、secretLevels[]、bizFilters[]、summaryText。

template/apply 响应:{ successCount, failures: [{ targetId, reason }] }。


十五、SQL 执行顺序

# 1. RBAC 数据权限表 + 种子
mysql ... < sql/install_data_permission.sql

# 2. OMS 业务表扩展列
mysql ... < sql/migrate_oms_data_permission_columns.sql

# 3. 菜单与 Admin 权限码
mysql ... < sql/seed_data_perm_rbac_menu.sql

PermissionDefinitionProvider 中注册 §14.9 权限码后,需重新分配角色或执行 seed 脚本。