28 KiB
FMS 权限体系设计文档
1. 设计目标
本权限体系用于 FMS / ERP 元数据驱动架构,核心目标:
- 操作权限与数据权限分离。
- 权限直接绑定菜单、动作、模块、字段、页面、报表等资源。
- Power ID 不要求人工维护,直接由资源类型、资源 ID 和操作组成。
- 用户直接授权,不引入角色继承。
- 数据权限独立于菜单,不因为用户从哪个菜单进入而改变数据范围。
- 用户个性化设置不能突破权限。
- 权限默认拒绝(Default Deny)。
2. 权限模型总览
整个权限体系分为两条线:
┌──────────────┐
│ 资源定义 │
└──────┬───────┘
│
┌──────────┼──────────┐
│ │ │
菜单/动作 模块/字段 页面/报表
│ │ │
└──────────┼──────────┘
↓
s_power
↓
s_user_power
↓
用户操作权限
┌──────────────┐
│ 数据模块 │
└──────┬───────┘
↓
s_user_data_scope
↓
s_user_data_scope
↓
数据范围
因此:
s_power:定义「能做什么」s_user_power:定义「用户能做什么」s_user_data_scope:定义「用户在某个模块、某个操作下可以作用于哪些数据」
3. Power ID 设计
3.1 核心原则
b_id 不再使用随机 ID,也不要求人工创建类似:
power_cw_fee_update
power_cw_fee_audit
power_cw_fee_amount_edit
而是直接使用稳定、可解析的权限编码。
统一格式:
menu.<MenuID>
action.<ActionID>
module.<ModuleID>.<Operation>
page.<PageID>
report.<ReportID>
3.2 Power ID 示例
菜单权限
menu.cw_fee
表示:可以进入 / 使用费用管理菜单。
动作权限
action.cw_fee_audit
表示:可以执行费用审核动作。
模块权限
module.cw_fee.read
module.cw_fee.create
module.cw_fee.update
module.cw_fee.delete
module.cw_fee.export
页面权限
page.cw_fee
报表权限
report.cw_fee_summary
4. Power 类型
| b_power_type | 用途 | ID 格式 |
|---|---|---|
| menu | 菜单入口 | menu.<MenuID> |
| action | 业务动作 | action.<ActionID> |
| module | 数据模块操作 | module.<ModuleID>.<Operation> |
| page | 页面入口 | page.<PageID> |
| report | 报表入口 | report.<ReportID> |
5. 操作权限语义
5.1 menu
menu.cw_fee
用于判断用户是否拥有菜单入口权限。
菜单权限只解决:
- 用户能不能进入这个菜单。
不负责:
- 数据范围
- 字段权限
- 审核权限
- 删除权限
5.2 action
例如:
action.cw_fee_audit
action.cw_fee_unaudit
action.cw_fee_writeoff
统一使用:
b_power_type = actionb_operation = execute
动作权限解决:用户能不能执行这个具体业务动作。
5.3 module
例如:
module.cw_fee.read
module.cw_fee.create
module.cw_fee.update
module.cw_fee.delete
module.cw_fee.export
模块权限解决:用户对该业务模块具有什么数据操作能力。
5.4 page
例如:
page.cw_fee
用于页面访问控制。
页面权限和菜单权限可以同时存在:
menu.cw_fee
page.cw_fee
菜单解决入口展示 / 进入菜单,页面解决具体页面访问。
5.5 report
例如:
report.cw_fee_summary
用于报表访问权限。
报表权限本身不等于数据权限。例如用户拥有 report.cw_fee_summary,还需要根据报表对应的数据模块执行数据范围控制。
6. 核心表结构
以下表结构暂时不加入索引、唯一约束、外键约束,后续根据实际运行情况再补充。
6.1 s_power
权限定义表。
create table dbo.s_power (
b_id varchar(300) not null,
b_name nvarchar(200) not null,
b_i18n varchar(150) null,
b_power_type varchar(20) not null,
-- menu / action / module / page / report
b_resource varchar(128) null,
-- action / page / report 等资源 ID
b_menu_id varchar(50) null,
-- 所属菜单,主要用于 menu / action
b_module_id varchar(50) null,
-- 所属业务模块
b_operation varchar(30) not null,
-- menu/page/report: access
-- action: execute
-- module: read/create/update/delete/export
b_canuse tinyint not null default 1,
b_xh int not null default 0
);
b_id 示例:
menu.cw_fee
action.cw_fee_audit
module.cw_fee.read
module.cw_fee.update
page.cw_fee
report.cw_fee_summary
这里的 b_id 就是 Power 的业务编码。
不再需要 power_cw_fee_update、power_cw_fee_audit 这种额外编码。
7. s_user_power
用户权限授权表。
create table dbo.s_user_power (
b_user_id varchar(50) not null,
b_power_id varchar(300) not null,
b_canuse tinyint not null default 1,
b_updatedatetime datetime2 null
);
语义:
- 存在有效记录 = 用户拥有权限
- 不存在记录 = 用户没有权限
b_canuse = 0= 当前授权无效
当前设计不增加 allow / deny,即采用:
默认拒绝,明确授权。
8. 数据权限
操作权限与数据权限必须分开。
例如:
module.cw_fee.read
只表示:用户具有读取费用数据的能力。
它并不表示:用户可以读取所有费用数据。
数据范围直接由 s_user_data_scope 控制。
9. s_user_data_scope
用户数据权限授权表。
create table dbo.s_user_data_scope (
b_user_id varchar(50) not null,
b_module_id varchar(50) not null,
b_operation varchar(30) not null,
-- * / read / create / update / delete / export;* 表示模块默认范围
b_scope_level varchar(10) not null default 'default',
-- default / override;default 使用 b_operation='*'
b_scope_no int not null default 1,
b_scope_type varchar(30) not null,
-- own / department / department_tree / all / custom
b_scope_field varchar(50) null,
b_scope_value varchar(100) null,
b_updatedatetime datetime2 null
);
多个同级范围同时存在时:
Scope A OR Scope B OR Scope C
例如:
张三
cw_fee
* / read / update
├── department
└── own
表示同一操作下多个范围按 OR 合并;具体操作没有 override 时回退到 b_operation='*' 的默认范围。
11. 完整示例
假设系统有:
- 模块:
cw_fee= 费用管理 - 菜单:
cw_fee= 费用管理 - 动作:
cw_fee_audit= 审核、cw_fee_unaudit= 反审核、cw_fee_writeoff= 核销 - 字段:
mx_amount= 金额
11.1 自动产生 Power
菜单:
menu.cw_fee
动作:
action.cw_fee_audit
action.cw_fee_unaudit
action.cw_fee_writeoff
模块:
module.cw_fee.read
module.cw_fee.create
module.cw_fee.update
module.cw_fee.delete
module.cw_fee.export
12. 用户授权示例
张三拥有:
menu.cw_feemodule.cw_fee.readmodule.cw_fee.updateaction.cw_fee_audit
insert into dbo.s_user_power (
b_user_id,
b_power_id,
b_canuse
)
values
('zhangsan', 'menu.cw_fee', 1),
('zhangsan', 'module.cw_fee.read', 1),
('zhangsan', 'module.cw_fee.update', 1),
('zhangsan', 'action.cw_fee_audit', 1);
张三没有 module.cw_fee.delete,并且金额字段策略为 view,所以:
- 不能删除费用
- 不能修改金额字段
13. 数据范围示例
直接授权:
insert into dbo.s_user_data_scope (
b_user_id,
b_module_id,
b_operation,
b_scope_level,
b_scope_no,
b_scope_type,
b_scope_field
)
values (
'zhangsan',
'cw_fee',
'*',
'default',
1,
'department',
'b_department_id'
);
此时张三拥有 module.cw_fee.read,并且 read 数据范围回退为本部门。若再增加 update + override + own,则修改范围只限本人创建的数据。
最终不是「张三可以读取全部费用」,而是「张三可以读取自己有权限范围内的费用」。
14. 权限执行顺序
一个业务操作建议按照以下顺序判断:
① 用户是否有效
↓
② 菜单 / 页面入口权限
↓
③ Action 权限
↓
④ Module 数据操作权限
↓
⑤ Field 字段权限
↓
⑥ Data Scope 数据范围
↓
⑦ 业务状态 / 业务规则
↓
⑧ 执行操作
例如「审核费用」:
用户
↓
menu.cw_fee
↓
page.cw_fee
↓
action.cw_fee_audit
↓
module.cw_fee.update
↓
数据范围
↓
费用当前状态 = 送审
↓
执行审核
15. 不同权限解决不同问题
| 问题 | 权限 |
|---|---|
| 能不能看到菜单 | menu.* |
| 能不能进入页面 | page.* |
| 能不能执行审核 | action.* |
| 能不能修改费用 | module.cw_fee.update |
| 能不能看到金额 | s_user_field_permission.b_access_mode in ('view','edit') |
| 能不能修改金额 | s_user_field_permission.b_access_mode = 'edit' |
| 能不能查询金额 | s_user_field_permission.b_allow_query = 1 |
| 能不能导出金额 | s_user_field_permission.b_allow_export = 1 |
| 能不能看报表 | report.* |
| 能看哪些数据 | s_user_data_scope |
16. 与元数据体系的关系
Power 不应该成为另一套独立的资源体系,而应该从现有元数据自动生成。
s_menu
↓
menu.<MenuID>
Action 定义
↓
action.<ActionID>
s_module
↓
module.<ModuleID>.<Operation>
Page 定义
↓
page.<PageID>
Report 定义
↓
report.<ReportID>
因此新增模块 cw_air_fee,系统可以自动注册:
module.cw_air_fee.read
module.cw_air_fee.create
module.cw_air_fee.update
module.cw_air_fee.delete
module.cw_air_fee.export
新增字段 mx_tax 后,由模块字段元数据和用户字段策略直接控制,不生成 s_power 权限点。
17. 权限与用户个性化的关系
用户个性化配置(s_user_field_pref、s_user_query_field_pref)只能调整:
- 显示
- 排序
- 宽度
- 查询字段默认状态
不能增加权限。
最终优先级:
字段 b_canuse
↓
权限
↓
系统默认布局
↓
用户个性化
例如:用户字段策略为 hidden 时,即使 s_user_field_pref.b_visible = 1,也不能显示金额字段。
18. 最终推荐的核心关系
┌───────────────┐
│ s_module │
└───────┬───────┘
│
├──────────────┐
↓ ↓
s_field
│
├──────────────┐
↓ ↓
s_power s_user_data_scope
│
↓
s_user_power
│
↓
b_user
菜单和动作:
s_menu
│
├── menu.<MenuID>
│
└── action.<ActionID>
↓
s_power
页面和报表:
page / report
↓
s_power
19. 最终结论
本设计的核心原则可以归纳为:
s_power.b_id是内部主键,s_power.b_code是系统生成的可读业务键;- 权限唯一性由资源类型、资源编码、owner 和能力字段共同保证;
- 字段权限直接使用
s_user_field_permission的访问策略; - 数据范围直接使用
s_user_data_scope,不再建立独立的范围模板表。
权限业务键示例:
menu.<MenuID>
action.<ActionID>
module.<ModuleID>.<Operation>
page.<PageID>
report.<ReportID>
其中:
s_power是统一权限注册表。s_user_power是用户操作权限。s_user_data_scope是用户数据范围授权。- 操作权限和数据权限完全分离。
- 菜单不负责数据范围。
- 用户个性化不能突破权限。
- 当前不引入角色继承。
- 后续如果增加角色,可以在
s_user_power之外增加角色授权层,而无需改变 Power 编码体系。
20. Demo 数据(4 张表)
以下为新权限模型的示例数据,沿用 cw_fee 费用模块。示例用户:张三(费用会计)、李四(财务经理)。数据范围直接保存在 s_user_data_scope,不再维护独立的范围模板表。
20.1 s_power(权限定义)
| b_id | b_code | b_name | b_power_type | b_resource_id | b_owner_type | b_owner_id | b_capability | b_canuse | b_xh |
|---|---|---|---|---|---|---|---|---|---|
| 1001 | menu.cw_fee.access | 费用管理菜单 | menu | cw_fee | null | null | access | 1 | 10 |
| 1002 | page.cw_fee.access | 费用页面 | page | cw_fee | null | null | access | 1 | 20 |
| 1003 | action.module.cw_fee.audit.execute | 费用审核 | action | audit | module | cw_fee | execute | 1 | 30 |
| 1004 | action.module.cw_fee.unaudit.execute | 费用反审核 | action | unaudit | module | cw_fee | execute | 1 | 40 |
| 1005 | module.cw_fee.read | 费用读取 | module | cw_fee | null | null | read | 1 | 50 |
| 1006 | module.cw_fee.create | 费用新增 | module | cw_fee | null | null | create | 1 | 60 |
| 1007 | module.cw_fee.update | 费用修改 | module | cw_fee | null | null | update | 1 | 70 |
| 1008 | module.cw_fee.delete | 费用删除 | module | cw_fee | null | null | delete | 1 | 80 |
| 1009 | module.cw_fee.export | 费用导出 | module | cw_fee | null | null | export | 1 | 90 |
| 1010 | report.cw_fee_summary.access | 费用汇总报表 | report | cw_fee_summary | null | null | access | 1 | 100 |
b_id 是内部主键,b_code 是全局唯一业务键。动作的 b_resource_id 是动作编码,b_owner_type/b_owner_id 标识所属模块;因此不同模块可以同时拥有 audit 动作而不冲突。
20.2 s_user_power(用户授权)
| b_user_id | b_power_id | b_canuse | b_updatedatetime |
|---|---|---|---|
| zhangsan | 1001 | 1 | 2026-02-01 09:00:00 |
| zhangsan | 1002 | 1 | 2026-02-01 09:00:00 |
| zhangsan | 1005 | 1 | 2026-02-01 09:00:00 |
| zhangsan | 1007 | 1 | 2026-02-01 09:00:00 |
| zhangsan | 1009 | 1 | 2026-02-01 09:00:00 |
| zhangsan | 1008 | 0 | 2026-02-10 14:30:00 |
| zhangsan | 1003 | 1 | 2026-02-01 09:00:00 |
| zhangsan | 1010 | 1 | 2026-02-01 09:00:00 |
| lisi | 1001 | 1 | 2026-01-15 10:00:00 |
| lisi | 1002 | 1 | 2026-01-15 10:00:00 |
| lisi | 1005 | 1 | 2026-01-15 10:00:00 |
| lisi | 1006 | 1 | 2026-01-15 10:00:00 |
| lisi | 1007 | 1 | 2026-01-15 10:00:00 |
| lisi | 1008 | 1 | 2026-01-15 10:00:00 |
| lisi | 1009 | 1 | 2026-01-15 10:00:00 |
| lisi | 1003 | 1 | 2026-01-15 10:00:00 |
| lisi | 1004 | 1 | 2026-01-15 10:00:00 |
| lisi | 1010 | 1 | 2026-01-15 10:00:00 |
张三的 1008 对应 module.cw_fee.delete,记录存在但已停用,因此仍然没有删除权限。
20.3 s_user_field_permission(字段访问策略)
| b_user_id | b_module_id | b_field | b_access_mode | b_allow_query | b_allow_export | b_canuse |
|---|---|---|---|---|---|---|
| zhangsan | cw_fee | mx_amount | view | 1 | 0 | 1 |
| zhangsan | cw_fee | mx_internal_cost | hidden | 0 | 0 | 1 |
| lisi | cw_fee | mx_amount | edit | 1 | 1 | 1 |
| lisi | cw_fee | mx_internal_cost | view | 1 | 0 | 1 |
张三对金额字段是“可见、只读、可查询、不可导出”;对内部成本字段完全不可见。李四可以编辑和导出金额,但内部成本字段仍然只读。
20.4 s_user_data_scope(用户数据范围授权)
| b_user_id | b_module_id | b_operation | b_scope_level | b_scope_type | b_scope_field | b_scope_value | b_scope_no | b_updatedatetime |
|---|---|---|---|---|---|---|---|---|
| zhangsan | cw_fee | * | default | department | b_department_id | null | 1 | 2026-02-01 09:00:00 |
| zhangsan | cw_fee | update | override | own | b_inputuser_id | null | 1 | 2026-02-01 09:00:00 |
| lisi | cw_fee | * | default | department_tree | b_department_id | null | 1 | 2026-01-15 10:00:00 |
| lisi | cw_fee | delete | override | all | null | null | 1 | 2026-01-15 10:00:00 |
要点:
- 张三使用模块默认范围读取本部门数据,但 update 有操作级覆盖,只能修改本人录入的费用;
- 李四使用默认范围处理一般操作,但 delete 有操作级覆盖为
all,经理可删全模块数据。
20.5 组合结果解读
| 能力 | 张三(费用会计) | 李四(财务经理) |
|---|---|---|
| 看菜单 / 页面 | ✅ | ✅ |
| 读取费用数据 | ✅ 本部门 | ✅ 本部门及下属部门 |
| 新增 | ❌ 无 module.create | ✅ |
| 修改 | ✅ 仅本人录入的单据 | ✅ 本部门及下属部门的单据 |
| 删除 | ❌ 授权已停用(b_canuse=0) | ✅ 全部数据 |
| 审核 / 反审核 | ✅ 可审核,❌ 不可反审核 | ✅ 都可以 |
| 金额字段 | 可见、只读、可查询、不可导出 | 可见、可编辑、可查询、可导出 |
| 内部成本字段 | 不可见 | 可见但只读 |
| 汇总报表 | ✅ | ✅(报表数据仍受 read 范围约束) |
21. 权限模型重构(当前生效方案)
21.1 重构原因
旧方案有两个结构性问题:
s_power.b_id同时承担数据库主键和业务权限编码。权限编码一旦变化会影响授权记录;动作编码在不同菜单/模块下重复时,action.<ActionID>也无法保证全局唯一。- 字段权限被拆成多个彼此独立的
view/edit/query/export权限点,不能直接表达“不可见”“可见但只读”“可见且可编辑”等实际权限状态,也容易出现edit=1、view=0这种无效组合。
新方案将“权限点身份”和“字段访问策略”分开:
s_power只保存菜单、页面、报表、模块、动作等可执行能力;s_user_field_permission保存字段访问级别及查询/导出能力;b_id只做内部主键,业务侧使用不可变且全局唯一的b_code;- 动作权限必须带上所属资源的命名空间,不再使用裸
action.<ActionID>。
21.2 s_power:内部主键与业务编码分离
create table dbo.s_power (
b_id bigint not null, -- 内部主键,雪花/序列生成,不表达业务含义
b_code varchar(300) not null, -- 稳定、全局唯一的业务键,由系统生成
b_name nvarchar(200) not null,
b_i18n varchar(150) null,
b_power_type varchar(20) not null, -- menu/page/report/module/action
b_resource_id varchar(128) not null, -- 当前权限对应的资源编码
b_owner_type varchar(20) null, -- action 的 owner 类型
b_owner_id varchar(128) null, -- action 的 owner 编码
b_capability varchar(30) not null, -- access/execute/read/create/update/delete/export
b_canuse tinyint not null default 1,
b_xh int not null default 0,
constraint PK_s_power primary key (b_id),
constraint UQ_s_power_code unique (b_code),
constraint CK_s_power_type check (b_power_type in ('menu','page','report','module','action')),
constraint CK_s_power_shape check (
(b_power_type in ('menu','page','report')
and b_owner_type is null and b_owner_id is null
and b_capability = 'access')
or (b_power_type = 'module'
and b_owner_type is null and b_owner_id is null
and b_capability in ('read','create','update','delete','export'))
or (b_power_type = 'action'
and b_owner_type in ('menu','page','module')
and b_owner_id is not null
and b_capability = 'execute')
)
);
create index IX_s_power_resource
on dbo.s_power (b_power_type, b_owner_type, b_owner_id, b_resource_id, b_canuse);
b_code 是由结构化身份规范化生成的唯一键,不允许人工随意修改。资源编码应使用稳定的业务键(建议只允许字母、数字、_、-),更名应通过资源迁移完成,而不是直接改写已发布权限的身份。推荐格式:
menu.cw_fee.access
page.cw_fee.access
report.cw_fee_summary.access
module.cw_fee.read
action.module.cw_fee.audit.execute
动作至少包含 owner_type + owner_id + action_id 三段。两个模块都可以定义 audit,但它们会生成不同的 b_code。跨多个资源的动作必须为每个资源建立独立权限点,或指定明确的系统级 owner。
21.3 s_user_power:引用内部主键
create table dbo.s_user_power (
b_user_id varchar(50) not null,
b_power_id bigint not null,
b_canuse tinyint not null default 1,
b_updatedatetime datetime2 null,
constraint PK_s_user_power primary key (b_user_id, b_power_id)
);
create index IX_s_user_power_user
on dbo.s_user_power (b_user_id, b_canuse, b_power_id);
授权、审计和关联查询使用 b_power_id;接口、缓存键、日志中需要可读标识时使用 s_power.b_code。权限名称或编码生成规则变化不会破坏数据库关联。
21.4 字段权限独立为访问策略
字段权限是有顺序的访问级别,不是四个互不相关的动作。新增用户字段策略表:
create table dbo.s_user_field_permission (
b_user_id varchar(50) not null,
b_module_id varchar(50) not null,
b_field varchar(128) not null,
b_access_mode varchar(10) not null, -- hidden / view / edit
b_allow_query tinyint not null default 0,
b_allow_export tinyint not null default 0,
b_canuse tinyint not null default 1,
b_updatedatetime datetime2 null,
constraint PK_s_user_field_permission
primary key (b_user_id, b_module_id, b_field),
constraint CK_s_user_field_permission_mode
check (b_access_mode in ('hidden','view','edit')),
constraint CK_s_user_field_permission_capability
check (b_access_mode <> 'hidden' or (b_allow_query = 0 and b_allow_export = 0))
);
create index IX_s_user_field_permission_module
on dbo.s_user_field_permission (b_user_id, b_module_id, b_canuse, b_field);
b_access_mode |
返回字段 | 页面显示 | 可编辑 |
|---|---|---|---|
hidden |
否 | 否 | 否 |
view |
是 | 是 | 否 |
edit |
是 | 是 | 是 |
b_allow_query 和 b_allow_export 是附加能力,不能把 hidden 字段变成可查询或可导出字段。没有有效记录时按 hidden 处理。
系统元数据中的 s_field_view、s_field_edit、s_field_query 仍然只负责默认布局、只读、禁用和查询布局,不承担用户授权。最终字段状态按以下规则计算:
用户字段策略(hidden/view/edit)
↓
模块字段元数据:b_visible、b_readonly、b_disabled(只能收紧)
↓
业务状态与业务规则
↓
最终字段状态
因此 edit 遇到 b_readonly=1 或 b_disabled=1 时降为 view,b_visible=0 时最终为 hidden。用户个性化不能恢复 hidden 字段,也不能把 view 变成 edit。
21.5 字段授权示例
insert into dbo.s_user_field_permission
(b_user_id, b_module_id, b_field, b_access_mode, b_allow_query, b_allow_export)
values
('zhangsan', 'cw_fee', 'mx_amount', 'view', 1, 0),
('lisi', 'cw_fee', 'mx_amount', 'edit', 1, 1);
写接口必须同时检查 module.<module>.update、字段最终为 edit、以及 update 数据范围。
21.6 权限判定顺序(重构后)
① 用户有效
② menu/page/report 入口权限(如适用)
③ action 权限(如适用)
④ module 操作权限
⑤ 字段策略:hidden / view / edit + query/export
⑥ 数据范围
⑦ 元数据只读/禁用、业务状态和业务规则
⑧ 执行操作
入口权限、模块权限、字段策略、数据范围是 AND 关系;同一用户多个数据范围仍按 OR 合并。
21.7 旧数据迁移规则
- 原
s_power.b_id字符串迁移到新表的b_code;新b_id重新生成,s_user_power.b_power_id通过旧编码映射到新主键。 - 原
action.<ActionID>根据b_module_id或菜单归属补全 owner,生成action.<OwnerType>.<OwnerID>.<ActionID>.execute。无法唯一确定归属的记录不得自动合并。 - 原字段权限按用户、模块、字段聚合:有有效
edit则为edit,否则有有效view则为view,否则为hidden;query、export映射到附加标志,并受hidden约束。 - 迁移完成后旧字段权限记录删除或归档,权限服务只读取新模型,避免新旧模型同时生效。
21.8 数据范围配置 UI:默认范围 + 操作级覆盖
数据范围底层仍按“模块 + 操作”保存,但管理界面不要求管理员一开始就配置每个操作。采用两层配置:
默认配置
用户选择一个模块后,先设置一个默认数据范围:
默认数据范围:仅本人 / 仅本部门 / 本部门及下属 / 全部 / 自定义
默认范围应用于该模块所有需要数据过滤的操作。底层只保存一条模块默认记录:
* -> 默认范围
对于不适用的操作(例如用户没有 module.<module>.delete),不生成数据范围记录也不会产生权限。
操作级覆盖
在默认范围旁提供“按操作单独设置”入口。管理员展开后,可以针对具体操作覆盖默认值:
查询 read :跟随默认范围 = 本部门
新增 create :跟随默认范围
修改 update :仅本人
删除 delete :无权限或不配置
导出 export :跟随默认范围 = 本部门
操作级覆盖只改变该操作的数据过滤条件,不会授予操作权限。用户仍然必须拥有对应的 s_power 权限。
保存与读取规则
s_user_data_scope 使用来源标识和通配操作,区分默认值和覆盖值:
b_scope_level varchar(10) not null default 'default'
-- default = 来自模块默认范围
-- override = 操作级覆盖
b_operation = '*'
-- 仅 default 级别允许使用 '*'
同一用户、模块、操作最多保留一组生效配置:
- 没有具体操作的
override记录时,运行时回退到b_operation='*'的default范围; - 存在
override记录时,只对该操作使用覆盖范围; - 一个操作可以配置多条范围,多条范围之间仍按
OR合并; - UI 中的“无权限”表示不生成该操作的范围,同时仍以
s_user_power为最终操作权限判断依据。
典型示例
管理员只配置:
cw_fee 默认数据范围 = 本部门
然后展开操作级配置,将修改覆盖为“仅本人”:
s_user_data_scope
cw_fee + * + department (default)
cw_fee + update + own (override)
最终效果就是:张三可以查询和导出本部门费用,但只能修改本人创建的费用。这个例子也是保留操作级数据范围能力的主要原因。