数据权限功能设计方案(一)---升鲜宝生鲜配送供应链管理系统
数据权限功能设计方案(一)---升鲜宝生鲜配送供应链管理系统
适用范围:升鲜宝供应链管理系统 / SaaS 多租户 / PC管理端 / 手机端 / POS端 / 供应商端 / 客户端
文档版本:V1.0 生成日期:2024-04-28
建设目标:把“分散在各业务 SQL、Controller、Service 中的权限判断”,升级为“统一权限平台化组件”,让业务模块只声明场景,平台自动完成权限判断、SQL改写、字段过滤、脱敏、导出控制、报表控制、审计与越权告警。
|
项目 |
内容 |
|
系统名称 |
升鲜宝供应链管理系统 |
|
组件名称 |
统一权限平台化组件 |
|
技术栈建议 |
Spring Boot + Spring Security + JWT + MyBatis-Plus + Redis + Caffeine + MySQL 8.0 |
|
核心能力 |
菜单权限、按钮权限、场景权限、数据权限、字段权限、导出权限、报表权限、数据脱敏、审计告警 |
|
落地原则 |
不改变现有 Controller 方法签名;通过注解、场景编码、SQL拦截器与上下文自动完成权限治理 |
目录
1. 建设背景与目标
2. 总体设计原则
3. 统一权限平台总体架构
4. 权限核心模型设计
5. 功能模块详细设计
6. 数据权限引擎详细设计
7. 字段权限与数据脱敏设计
8. 导出权限与导出安全设计
9. 报表权限设计
10. 审计日志与越权告警设计
11. 数据库表结构设计
12. Java 工程结构与核心接口设计
13. MyBatis-Plus 拦截器与 SQL 改写设计
14. 缓存与权限变更刷新机制
15. 管理后台功能设计
16. 升鲜宝业务模块接入清单
17. 场景编码规范与初始化建议
18. 迁移实施路线
19. 测试验收清单
20. 风险控制与最佳实践
附录 A. 枚举规范
附录 B. 配置文件示例
附录 C. 典型业务接入代码示例
1. 建设背景与目标
1.1 当前系统常见问题
升鲜宝供应链管理系统已经覆盖商品、客户、供应商、销售、采购、仓库、门店仓、POS、财务、报表、导入导出等多个业务域。随着系统规模扩大,如果每个模块自行拼接权限条件,会逐步产生以下问题:
- 权限逻辑散落在 Controller、Service、Mapper XML 中,后续很难统一排查和升级。
- 同一个接口在不同业务场景下权限不同,例如商品列表既用于商品管理,也用于销售开单、采购开单、POS 收银。
- 导出、报表、打印、分享码查看等高风险场景容易复用普通列表权限,存在批量泄露风险。
- 字段权限和数据脱敏没有统一入口,例如成本价、毛利、客户手机号、供应商联系人等敏感字段难以集中控制。
- 无法统一记录“谁在什么场景下看了什么数据、导出了什么数据、是否命中越权规则”。
- 多租户、门店、仓库、客户、供应商、货主、业务员等多维权限并存,靠手写 SQL 难以长期维护。
1.2 建设目标
统一权限平台化组件的建设目标,是将权限从“业务代码中的局部判断”升级为“平台化基础能力”。
|
目标 |
说明 |
|
统一入口 |
所有页面、按钮、查询、导出、报表、打印、分享码访问统一进入权限平台判断。 |
|
统一场景 |
通过 scene_code 区分业务场景,同一个接口可在不同场景下使用不同权限策略。 |
|
统一拦截 |
通过 MyBatis-Plus InnerInterceptor 自动改写 SQL,减少业务 SQL 中硬编码权限条件。 |
|
统一字段控制 |
通过字段权限规则控制字段可见、隐藏、只读、可编辑和脱敏。 |
|
统一导出安全 |
导出使用独立权限场景,支持行数限制、字段控制、审批、水印、频率限制和审计。 |
|
统一报表安全 |
报表权限控制报表入口、指标、维度、导出、分享。 |
|
统一审计告警 |
权限命中、跳过、失败、越权、导出敏感字段等行为统一记录并告警。 |
|
统一缓存 |
Redis + Caffeine 组合缓存权限规则,权限变更后实时刷新。 |
最终效果:业务模块只声明“当前是什么场景”,权限平台自动完成判断、SQL改写、字段过滤、脱敏、审计和告警。
2. 总体设计原则
|
原则 |
说明 |
|
默认拒绝 |
未配置权限策略、SQL解析失败、数据范围为空时,默认拒绝访问,避免漏配导致越权。 |
|
业务无侵入 |
不强制修改现有 Controller 方法签名,主要通过注解、上下文和拦截器接入。 |
|
场景优先 |
权限判断以 scene_code 为核心,而不是只看 URL 或 Mapper 方法。 |
|
主表优先 |
多表 JOIN 查询默认优先对主业务表追加权限条件,必要时可配置 JOIN 表权限。 |
|
配置化优先 |
常见权限策略通过表配置,特殊复杂场景可扩展安全 SQL 或业务 Resolver。 |
|
导出独立 |
导出、报表、分享、打印等高风险场景不能简单复用列表权限。 |
|
审计闭环 |
权限命中、忽略、拒绝、异常、导出、报表访问都要形成审计闭环。 |
|
缓存可控 |
权限缓存要支持租户、用户、角色、场景、字段、导出规则维度的精准刷新。 |
|
可演进 |
先落地数据权限,再逐步扩展字段权限、脱敏、导出、报表和告警。 |
3. 统一权限平台总体架构
统一权限平台建议作为升鲜宝基础组件独立建设,可以放在 sxb-auth 或 sxb-permission 模块中,并被 PMS、CRM、SUP、OMS、PUR、WMS、HWMS、POS、COST、FIN、REPORT、EXPORT 等模块引用。
3.1 平台架构图
用户请求 / API / 导出 / 报表 / 打印 / 分享码
↓
Spring Security + JWT 解析登录身份
↓
PermissionContextFactory 构建统一权限上下文
↓
PermissionSceneResolver 解析 scene_code / resource_code
↓
PermissionPlatformFacade 统一权限门面
├─ MenuPermissionEngine 菜单权限
├─ ButtonPermissionEngine 按钮权限
├─ DataPermissionEngine 数据权限
├─ FieldPermissionEngine 字段权限
├─ ExportPermissionEngine 导出权限
├─ ReportPermissionEngine 报表权限
├─ MaskingEngine 数据脱敏
└─ AlertAuditEngine 审计与越权告警
↓
MyBatis-Plus InnerInterceptor SQL 自动改写
↓
数据库查询 / 业务处理
↓
返回结果字段过滤 + 脱敏
↓
审计日志 / 越权告警 / 缓存刷新
3.2 平台模块划分
|
模块 |
职责 |
|
权限上下文中心 |
解析用户、租户、公司、组织、门店、仓库、员工、角色、终端等信息。 |
|
场景权限中心 |
统一维护 scene_code、请求路径、资源、终端、场景类型。 |
|
数据权限中心 |
根据策略和规则生成 SQL 条件,并交给拦截器改写 SQL。 |
|
字段权限中心 |
控制字段可见、隐藏、只读、可编辑、脱敏。 |
|
导出权限中心 |
控制导出开关、导出范围、导出字段、单次行数、频率、审批和水印。 |
|
报表权限中心 |
控制报表访问、指标、维度、导出和分享。 |
|
数据脱敏中心 |
手机号、身份证、银行卡、地址、金额、成本、毛利等字段脱敏。 |
|
权限审计中心 |
记录命中策略、原始SQL、最终SQL、访问人、场景、结果。 |
|
越权告警中心 |
对跨租户、导出敏感字段、SQL解析失败、无权限访问等风险告警。 |
|
缓存刷新中心 |
基于 Redis Pub/Sub 或 Stream 进行分布式权限缓存刷新。 |
4. 权限核心模型设计
4.1 权限主体模型
权限主体表示“谁在访问系统”。升鲜宝不应只支持内部员工,还要支持老板、店长、仓管员、业务员、采购员、司机、供应商、客户、团长等不同身份。
|
主体类型 |
说明 |
典型场景 |
|
USER |
系统用户 |
PC 管理端员工登录 |
|
ROLE |
角色 |
老板、店长、仓管员、财务、业务员 |
|
POSITION |
岗位 |
采购岗、仓库岗、财务岗 |
|
ORG |
组织 |
总部、分公司、部门 |
|
SHOP |
门店 |
门店仓、POS、门店商城 |
|
SUPPLIER |
供应商 |
供应商协同端 |
|
CUSTOMER |
客户 |
客户下单端、对账端 |
|
DRIVER |
司机 |
配送任务、签收回传 |
|
TENANT_ADMIN |
租户管理员 |
租户级系统配置 |
|
SUPER_ADMIN |
平台超级管理员 |
运维后台 |
4.2 权限资源模型
|
资源类型 |
说明 |
示例 |
|
MENU |
菜单资源 |
销售订单、采购订单、库存查询、客户管理 |
|
BUTTON |
按钮资源 |
新增、编辑、删除、审核、反审核、导出、打印 |
|
API |
接口资源 |
/api/oms/order/page |
|
DATA_TABLE |
数据表资源 |
oms_order、pms_goods、crm_customer |
|
DATA_FIELD |
字段资源 |
cost_price、profit_amount、mobile |
|
REPORT |
报表资源 |
老板驾驶舱、销售汇总、库存成本 |
|
EXPORT |
导出资源 |
销售订单导出、客户导出、库存导出 |
|
|
打印资源 |
销售小票、配送单、采购单 |
|
SHARE |
分享资源 |
分享码查看订单、客户对账单分享 |
4.3 场景模型
场景是统一权限平台的核心。场景用于描述“在什么业务入口、什么终端、用什么方式访问什么资源”。
scene_code 推荐格式:模块:业务对象:动作[:扩展场景]
示例:
pms:goods:manage:list 商品管理列表
oms:sale-order:select-goods 销售开单选择商品
wms:stockout:select-goods 销售出库选择商品
pos:cashier:select-goods POS 收银选择商品
oms:sale-order:export 销售订单导出
report:boss-dashboard:view 老板驾驶舱查看
4.4 策略与规则模型
策略是权限规则的集合,规则是具体条件。一个策略可以包含多个规则,规则之间支持 AND / OR 组合。
|
模型 |
说明 |
|
Policy |
策略,例如“店长销售订单数据权限”“仓管员库存数据权限”。 |
|
Rule |
规则,例如 tenant_id = 当前租户,shop_id = 当前门店,warehouse_id IN 授权仓库。 |
|
Grant |
授权数据,例如某用户授权门店 1、2、3,授权仓库 A、B。 |
|
TableMapping |
表字段映射,告诉引擎 oms_order 的 shop 维度字段是 shop_id。 |
|
ScenePolicy |
场景和策略绑定,支持用户、角色、岗位、组织、默认策略。 |
5. 功能模块详细设计
|
功能模块 |
详细说明 |
|
菜单权限 |
控制是否能看到某个菜单页面。菜单权限是入口权限,不等于数据权限。 |
|
按钮权限 |
控制新增、编辑、删除、审核、反审核、导出、打印等操作按钮。 |
|
场景权限 |
控制用户是否允许进入某个业务场景,例如“销售开单选择商品”。 |
|
数据权限 |
控制用户能够查询到哪些业务数据。通过 SQL 拦截器实现。 |
|
字段权限 |
控制返回结果中字段是否可见、是否只读、是否脱敏。 |
|
导出权限 |
独立控制导出数据范围、字段、行数、频率、审批和水印。 |
|
报表权限 |
控制报表入口、指标、维度、导出和分享。 |
|
数据脱敏 |
对手机号、地址、成本价、毛利等字段做动态脱敏。 |
|
审计日志 |
记录权限命中、跳过、拒绝、异常、导出、报表访问等行为。 |
|
越权告警 |
识别跨租户、跨供应商、跨客户、敏感字段导出等风险。 |
5.1 菜单权限、按钮权限、数据权限、字段权限的边界
|
权限类型 |
解决的问题 |
不解决的问题 |
|
菜单权限 |
能不能进入页面 |
进入页面后能看哪些数据 |
|
按钮权限 |
能不能点击某个操作 |
点击后涉及哪些数据范围 |
|
数据权限 |
能看到哪些记录 |
记录里的字段是否敏感 |
|
字段权限 |
能看到哪些字段、字段是否脱敏 |
记录范围过滤 |
|
导出权限 |
能不能批量导出及导出安全限制 |
页面入口权限 |
|
报表权限 |
能看哪些指标和维度 |
原始业务表维护权限 |
设计重点:菜单权限、按钮权限、数据权限、字段权限不能混为一谈,但必须共享同一套用户上下文、场景编码、审计日志和缓存刷新机制。
6. 数据权限引擎详细设计
6.1 数据范围类型
|
范围类型 |
说明 |
典型字段 |
|
ALL |
全部数据 |
不追加权限条件 |
|
CURRENT_TENANT |
当前租户 |
tenant_id |
|
CURRENT_COMPANY |
当前公司 |
company_id |
|
CURRENT_ORG |
当前组织 |
org_id |
|
CURRENT_ORG_AND_CHILDREN |
当前组织及下级 |
org_id |
|
CURRENT_SHOP |
当前门店 |
shop_id |
|
ASSIGNED_SHOPS |
授权门店集合 |
shop_id IN (...) |
|
CURRENT_WAREHOUSE |
当前仓库 |
warehouse_id |
|
ASSIGNED_WAREHOUSES |
授权仓库集合 |
warehouse_id IN (...) |
|
CREATED_BY_SELF |
本人创建 |
create_user_id |
|
SALESMAN_SELF |
当前业务员 |
salesman_id |
|
ASSIGNED_CUSTOMERS |
授权客户集合 |
customer_id IN (...) |
|
ASSIGNED_SUPPLIERS |
授权供应商集合 |
supplier_id IN (...) |
|
CUSTOM_SAFE_SQL |
自定义安全 SQL |
EXISTS / 子查询 |
|
NONE |
无数据权限 |
1 = 0 |
6.2 数据权限解析流程
1. 根据请求构建 PermissionContext
2. 根据注解、QueryFacade 或 URL 解析 scene_code
3. 根据 scene_code 查询场景配置
4. 根据用户、角色、岗位、组织解析命中的策略
5. 读取策略下的规则
6. 读取表字段映射,确认 table / alias / column
7. 从登录上下文或授权表读取权限值
8. 组装 SQL 条件
9. 交给 MyBatis-Plus InnerInterceptor 改写 SQL
10. 记录权限命中审计
6.3 单表查询改写示例
原始 SQL:
SELECT id, goods_name, sale_price
FROM pms_goods
WHERE deleted = 0;
改写后:
SELECT id, goods_name, sale_price
FROM pms_goods
WHERE deleted = 0
AND tenant_id = 10001
AND company_id = 20001;
6.4 多表 JOIN 查询改写示例
原始 SQL:
SELECT o.id, o.order_no, c.customer_name, s.shop_name
FROM oms_order o
LEFT JOIN crm_customer c ON o.customer_id = c.id
LEFT JOIN mall_shop s ON o.shop_id = s.id
WHERE o.deleted = 0;
改写后:
SELECT o.id, o.order_no, c.customer_name, s.shop_name
FROM oms_order o
LEFT JOIN crm_customer c ON o.customer_id = c.id
LEFT JOIN mall_shop s ON o.shop_id = s.id
WHERE o.deleted = 0
AND o.tenant_id = 10001
AND o.shop_id IN (10, 11, 12);
6.5 数据权限默认拒绝策略
当权限策略不存在、数据授权为空、SQL解析失败、场景编码缺失时,建议按 default-mode=deny 处理。特殊公共接口必须显式配置白名单或使用带原因的 @DataPermissionIgnore。
7. 字段权限与数据脱敏设计
7.1 字段权限类型
|
类型 |
说明 |
示例 |
|
VISIBLE |
字段可见 |
销售金额、订单状态 |
|
HIDDEN |
字段隐藏 |
成本价、毛利、内部备注 |
|
READONLY |
字段只读 |
审核后的订单金额 |
|
EDITABLE |
字段可编辑 |
未审核订单备注 |
|
MASK |
字段脱敏 |
手机号、地址、银行卡、成本价 |
7.2 敏感字段建议分级
|
敏感等级 |
字段类型 |
处理建议 |
|
S1 普通 |
订单号、商品名称、单位 |
正常展示 |
|
S2 业务敏感 |
客户手机号、联系人、地址 |
按角色脱敏或隐藏 |
|
S3 经营敏感 |
成本价、毛利、利润率、供应商采购价 |
老板/财务可见,其他隐藏或脱敏 |
|
S4 高敏感 |
银行卡、身份证、平台密钥 |
默认隐藏,特殊审批后查看 |
7.3 字段权限处理流程
查询数据完成
↓
根据 scene_code + subject 解析字段权限规则
↓
隐藏字段:从 VO / Map 中移除或置空
↓
脱敏字段:根据 mask_rule_code 调用脱敏处理器
↓
只读字段:返回给前端 readonly 标记
↓
记录字段权限命中审计
7.4 常见脱敏规则
|
字段 |
脱敏效果 |
规则 |
|
手机号 |
138****8888 |
保留前3位后4位 |
|
身份证 |
3301************22 |
保留前4位后2位 |
|
银行卡 |
6222 **** **** 8888 |
分段掩码 |
|
姓名 |
张* / 王** |
保留姓氏 |
|
地址 |
浙江省杭州市*** |
保留省市 |
|
成本价 |
*** |
完全隐藏 |
|
毛利率 |
*** |
完全隐藏 |
8. 导出权限与导出安全设计
导出权限必须独立于列表权限。列表查询通常是分页查看,导出是批量转移数据,风险等级更高。
8.1 导出控制项
|
控制项 |
说明 |
|
是否允许导出 |
根据按钮权限 + 导出场景权限判断。 |
|
导出数据范围 |
使用独立的 export scene 进行数据权限解析。 |
|
导出字段范围 |
结合字段权限决定是否导出成本、毛利、电话、地址。 |
|
单次最大行数 |
例如普通员工 1000 行,老板 10000 行。 |
|
每日导出次数 |
防止短时间内批量导出。 |
|
导出审批 |
敏感字段或超大数据量导出需要审批。 |
|
文件水印 |
加入导出人、时间、租户、IP、用途。 |
|
导出日志 |
记录导出条件、字段、数量、文件、权限策略。 |
8.2 导出任务流程
用户点击导出
↓
校验按钮权限 oms:sale-order:export
↓
校验导出场景权限
↓
校验导出规则:行数、次数、字段、是否审批
↓
创建导出任务
↓
异步执行查询,套用数据权限 SQL
↓
套用字段权限和脱敏规则
↓
生成 Excel / PDF / 图片 / ZIP
↓
添加水印
↓
记录导出审计
↓
用户下载文件
8.3 导出安全建议
- 导出接口必须使用独立 scene_code,例如 oms:sale-order:export,不要复用 oms:sale-order:list。
- 导出字段由后端白名单控制,前端传字段只能作为选择项,不能直接信任。
- 导出任务应进入导出中心,记录导出状态、条件、字段、数量、文件路径和操作人。
- 敏感字段导出建议默认脱敏,若要导出明文,必须有高权限或审批。
- 导出文件建议设置有效期,过期自动清理。
9. 报表权限设计
报表权限比普通列表更敏感,因为报表通常包含销售额、成本、毛利、库存成本、应收应付、客户对账、供应商对账等经营指标。
9.1 报表权限维度
|
维度 |
说明 |
示例 |
|
访问权限 |
能不能打开报表 |
老板驾驶舱查看权限 |
|
数据范围 |
报表统计的数据范围 |
全公司、门店、业务员、客户 |
|
指标权限 |
能不能看某些指标 |
毛利、成本、利润率 |
|
维度权限 |
能不能按某些维度展开 |
按客户、门店、商品、业务员 |
|
导出权限 |
能不能导出报表 |
销售汇总导出 |
|
分享权限 |
能不能生成分享码 |
客户对账单分享 |
9.2 报表权限示例
|
角色 |
可看报表 |
指标权限 |
数据范围 |
|
老板 |
老板驾驶舱、销售、库存、财务 |
全部指标 |
全公司 |
|
店长 |
门店销售、门店库存 |
销售额、数量,不看毛利 |
当前门店 |
|
业务员 |
个人业绩、客户销售 |
销售额、回款,不看成本 |
本人负责客户 |
|
仓管员 |
库存、出入库 |
库存数量,不看库存成本 |
授权仓库 |
|
财务 |
应收、应付、利润、成本 |
财务指标 |
授权结算组织 |
10. 审计日志与越权告警设计
10.1 审计日志内容
|
审计项 |
说明 |
|
用户信息 |
user_id、employee_id、role_ids、terminal_type、request_ip。 |
|
场景信息 |
scene_code、resource_code、request_path、mapper_id。 |
|
权限策略 |
policy_code、hit_rule_codes、scope_type。 |
|
SQL信息 |
original_sql、final_sql、sql_parse_result。 |
|
字段权限 |
hidden_fields、mask_fields、readonly_fields。 |
|
导出信息 |
export_task_id、export_rows、export_fields、file_url。 |
|
结果状态 |
PASS、DENY、SKIP、ERROR。 |
|
异常信息 |
deny_reason、error_message。 |
10.2 越权告警类型
|
告警类型 |
触发条件 |
级别 |
|
ACCESS_DENY |
无权限访问接口或场景 |
MIDDLE |
|
DATA_SCOPE_EMPTY |
数据范围为空但仍尝试查询 |
MIDDLE |
|
SQL_PARSE_ERROR |
SQL 无法解析或无法安全改写 |
HIGH |
|
CROSS_TENANT_RISK |
疑似跨租户访问 |
CRITICAL |
|
SUPPLIER_CROSS_ACCESS |
供应商访问非自己订单 |
HIGH |
|
CUSTOMER_CROSS_ACCESS |
客户访问非自己订单 |
HIGH |
|
EXPORT_OVER_LIMIT |
导出超过行数或频率限制 |
HIGH |
|
EXPORT_SENSITIVE_FIELD |
导出敏感字段 |
HIGH |
|
IGNORE_PERMISSION_USED |
使用权限忽略注解 |
MIDDLE |
10.3 告警处理闭环
发现风险
↓
写入 sxb_perm_security_alert
↓
通知系统管理员 / 安全负责人
↓
人工确认:误报 / 真实风险
↓
处理:封禁账号 / 调整权限 / 修复配置 / 加强规则
↓
记录处理人、处理时间、处理意见
↓
形成权限治理报表
11. 数据库表结构设计
数据库设计采用 sxb_perm_ 前缀,建议独立归属权限平台模块。以下为核心表结构,正式落地时可根据现有用户、角色、菜单表做复用或迁移。
11.1 核心表清单
|
表名 |
用途 |
|
sxb_perm_resource |
统一权限资源表,管理菜单、按钮、API、字段、导出、报表等资源。 |
|
sxb_perm_scene |
统一权限场景表,管理 scene_code 与请求路径、终端、场景类型。 |
|
sxb_perm_data_policy |
数据权限策略表。 |
|
sxb_perm_data_rule |
数据权限规则表。 |
|
sxb_perm_scene_policy |
场景策略绑定表。 |
|
sxb_perm_table_mapping |
表字段映射表,支持 SQL 别名和 JOIN 改写。 |
|
sxb_perm_data_grant |
用户/角色/岗位/组织的数据授权表。 |
|
sxb_perm_field_rule |
字段权限规则表。 |
|
sxb_perm_mask_rule |
脱敏规则表。 |
|
sxb_perm_export_rule |
导出权限规则表。 |
|
sxb_perm_report_rule |
报表权限规则表。 |
|
sxb_perm_audit_log |
权限审计日志表。 |
|
sxb_perm_security_alert |
越权告警表。 |
|
sxb_perm_cache_event |
权限缓存刷新事件表。 |
11.2 统一权限资源表 sxb_perm_resource
CREATE TABLE sxb_perm_resource (
id BIGINT NOT NULL COMMENT '主键ID',
resource_code VARCHAR(100) NOT NULL COMMENT '资源编码',
resource_name VARCHAR(100) NOT NULL COMMENT '资源名称',
resource_type VARCHAR(30) NOT NULL COMMENT '资源类型:MENU/BUTTON/API/DATA/FIELD/REPORT/EXPORT/PRINT/SHARE',
parent_id BIGINT DEFAULT 0 COMMENT '父级资源ID',
module_code VARCHAR(50) NOT NULL COMMENT '模块编码',
path VARCHAR(255) DEFAULT NULL COMMENT '路径',
permission_code VARCHAR(100) DEFAULT NULL COMMENT '权限编码',
sort_no INT NOT NULL DEFAULT 0 COMMENT '排序',
enabled TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用',
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
PRIMARY KEY (id),
UNIQUE KEY uk_resource_code (resource_code),
KEY idx_module_code (module_code),
KEY idx_resource_type (resource_type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='统一权限资源表';
11.3 统一权限场景表 sxb_perm_scene
CREATE TABLE sxb_perm_scene (
id BIGINT NOT NULL COMMENT '主键ID',
scene_code VARCHAR(100) NOT NULL COMMENT '场景编码',
scene_name VARCHAR(100) NOT NULL COMMENT '场景名称',
module_code VARCHAR(50) NOT NULL COMMENT '模块编码',
resource_code VARCHAR(100) DEFAULT NULL COMMENT '资源编码',
scene_type VARCHAR(30) NOT NULL COMMENT '场景类型:QUERY/DETAIL/EXPORT/REPORT/PRINT/SHARE/SELECT',
terminal_type VARCHAR(30) DEFAULT NULL COMMENT '终端类型:PC/MOBILE/POS/SUPPLIER/CUSTOMER/DRIVER',
request_method VARCHAR(20) DEFAULT NULL COMMENT '请求方法',
request_path VARCHAR(255) DEFAULT NULL COMMENT '请求路径',
default_mode VARCHAR(20) NOT NULL DEFAULT 'DENY' COMMENT '默认模式:ALLOW/DENY',
enabled TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用',
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
PRIMARY KEY (id),
UNIQUE KEY uk_scene_code (scene_code),
KEY idx_module_scene_type (module_code, scene_type),
KEY idx_request_path (request_path)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='统一权限场景表';
11.4 数据权限策略表 sxb_perm_data_policy
CREATE TABLE sxb_perm_data_policy (
id BIGINT NOT NULL COMMENT '主键ID',
policy_code VARCHAR(100) NOT NULL COMMENT '策略编码',
policy_name VARCHAR(100) NOT NULL COMMENT '策略名称',
policy_type VARCHAR(30) NOT NULL COMMENT '策略类型:SYSTEM/CUSTOM',
combine_mode VARCHAR(20) NOT NULL DEFAULT 'AND' COMMENT '规则组合:AND/OR',
priority INT NOT NULL DEFAULT 100 COMMENT '优先级',
enabled TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用',
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
PRIMARY KEY (id),
UNIQUE KEY uk_policy_code (policy_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据权限策略表';
11.5 数据权限规则表 sxb_perm_data_rule
CREATE TABLE sxb_perm_data_rule (
id BIGINT NOT NULL COMMENT '主键ID',
policy_id BIGINT NOT NULL COMMENT '策略ID',
rule_code VARCHAR(100) NOT NULL COMMENT '规则编码',
rule_name VARCHAR(100) NOT NULL COMMENT '规则名称',
table_name VARCHAR(100) NOT NULL COMMENT '表名',
table_alias VARCHAR(50) DEFAULT NULL COMMENT '表别名',
column_name VARCHAR(100) NOT NULL COMMENT '权限字段',
dimension_code VARCHAR(50) NOT NULL COMMENT '权限维度',
scope_type VARCHAR(50) NOT NULL COMMENT '范围类型',
operator VARCHAR(20) NOT NULL DEFAULT '=' COMMENT '操作符:=/IN/EXISTS/CUSTOM',
value_source VARCHAR(50) NOT NULL COMMENT '值来源:LOGIN/GRANT/STATIC/CUSTOM_SQL',
static_value VARCHAR(500) DEFAULT NULL COMMENT '静态值',
custom_sql TEXT DEFAULT NULL COMMENT '自定义安全SQL',
sort_no INT NOT NULL DEFAULT 0 COMMENT '排序',
enabled TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用',
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
PRIMARY KEY (id),
KEY idx_policy_id (policy_id),
KEY idx_table_column (table_name, column_name),
KEY idx_dimension_code (dimension_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据权限规则表';
11.6 场景策略绑定表 sxb_perm_scene_policy
CREATE TABLE sxb_perm_scene_policy (
id BIGINT NOT NULL COMMENT '主键ID',
scene_code VARCHAR(100) NOT NULL COMMENT '场景编码',
policy_id BIGINT NOT NULL COMMENT '策略ID',
subject_type VARCHAR(30) NOT NULL COMMENT '主体类型:USER/ROLE/ORG/POSITION/DEFAULT',
subject_id BIGINT DEFAULT NULL COMMENT '主体ID',
priority INT NOT NULL DEFAULT 100 COMMENT '优先级',
enabled TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
PRIMARY KEY (id),
KEY idx_scene_code (scene_code),
KEY idx_policy_id (policy_id),
KEY idx_subject (subject_type, subject_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='场景策略绑定表';
11.7 表字段映射表 sxb_perm_table_mapping
CREATE TABLE sxb_perm_table_mapping (
id BIGINT NOT NULL COMMENT '主键ID',
table_name VARCHAR(100) NOT NULL COMMENT '数据库表名',
table_desc VARCHAR(100) DEFAULT NULL COMMENT '表说明',
module_code VARCHAR(50) NOT NULL COMMENT '模块编码',
dimension_code VARCHAR(50) NOT NULL COMMENT '权限维度',
column_name VARCHAR(100) NOT NULL COMMENT '权限字段名',
required TINYINT NOT NULL DEFAULT 0 COMMENT '是否必须追加',
enabled TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用',
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
PRIMARY KEY (id),
UNIQUE KEY uk_table_dimension (table_name, dimension_code),
KEY idx_table_name (table_name),
KEY idx_dimension_code (dimension_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限表字段映射表';
11.8 数据授权表 sxb_perm_data_grant
CREATE TABLE sxb_perm_data_grant (
id BIGINT NOT NULL COMMENT '主键ID',
tenant_id BIGINT NOT NULL COMMENT '租户ID',
subject_type VARCHAR(30) NOT NULL COMMENT '主体类型:USER/ROLE/POSITION/ORG',
subject_id BIGINT NOT NULL COMMENT '主体ID',
dimension_code VARCHAR(50) NOT NULL COMMENT '数据维度:shop/warehouse/customer/supplier/owner',
biz_id BIGINT NOT NULL COMMENT '业务数据ID',
biz_name VARCHAR(100) DEFAULT NULL COMMENT '业务数据名称',
grant_source VARCHAR(30) NOT NULL DEFAULT 'MANUAL' COMMENT '授权来源:MANUAL/ROLE/ORG/AUTO',
enabled TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用',
expire_time DATETIME DEFAULT NULL COMMENT '过期时间',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
PRIMARY KEY (id),
UNIQUE KEY uk_subject_dimension_biz (tenant_id, subject_type, subject_id, dimension_code, biz_id),
KEY idx_subject (tenant_id, subject_type, subject_id),
KEY idx_dimension_biz (tenant_id, dimension_code, biz_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据授权表';
11.9 字段权限规则表 sxb_perm_field_rule
CREATE TABLE sxb_perm_field_rule (
id BIGINT NOT NULL COMMENT '主键ID',
scene_code VARCHAR(100) NOT NULL COMMENT '场景编码',
subject_type VARCHAR(30) NOT NULL COMMENT '主体类型:USER/ROLE/POSITION/ORG',
subject_id BIGINT NOT NULL COMMENT '主体ID',
table_name VARCHAR(100) NOT NULL COMMENT '表名',
field_name VARCHAR(100) NOT NULL COMMENT '字段名',
field_label VARCHAR(100) DEFAULT NULL COMMENT '字段显示名称',
permission_type VARCHAR(30) NOT NULL COMMENT '权限类型:VISIBLE/HIDDEN/READONLY/EDITABLE/MASK',
mask_rule_code VARCHAR(100) DEFAULT NULL COMMENT '脱敏规则编码',
priority INT NOT NULL DEFAULT 100 COMMENT '优先级',
enabled TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用',
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
PRIMARY KEY (id),
KEY idx_scene_subject (scene_code, subject_type, subject_id),
KEY idx_table_field (table_name, field_name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='字段权限规则表';
11.10 脱敏规则表 sxb_perm_mask_rule
CREATE TABLE sxb_perm_mask_rule (
id BIGINT NOT NULL COMMENT '主键ID',
mask_rule_code VARCHAR(100) NOT NULL COMMENT '脱敏规则编码',
mask_rule_name VARCHAR(100) NOT NULL COMMENT '脱敏规则名称',
mask_type VARCHAR(50) NOT NULL COMMENT '脱敏类型:MOBILE/ID_CARD/BANK_CARD/NAME/ADDRESS/AMOUNT/CUSTOM',
prefix_len INT DEFAULT 0 COMMENT '保留前几位',
suffix_len INT DEFAULT 0 COMMENT '保留后几位',
mask_char VARCHAR(10) NOT NULL DEFAULT '*' COMMENT '脱敏字符',
custom_expression VARCHAR(500) DEFAULT NULL COMMENT '自定义表达式',
enabled TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用',
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
PRIMARY KEY (id),
UNIQUE KEY uk_mask_rule_code (mask_rule_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='脱敏规则表';
11.11 导出权限规则表 sxb_perm_export_rule
CREATE TABLE sxb_perm_export_rule (
id BIGINT NOT NULL COMMENT '主键ID',
scene_code VARCHAR(100) NOT NULL COMMENT '导出场景编码',
subject_type VARCHAR(30) NOT NULL COMMENT '主体类型:USER/ROLE/POSITION/ORG',
subject_id BIGINT NOT NULL COMMENT '主体ID',
allow_export TINYINT NOT NULL DEFAULT 0 COMMENT '是否允许导出',
max_rows INT DEFAULT 1000 COMMENT '单次最大导出行数',
daily_max_times INT DEFAULT 10 COMMENT '每日最大导出次数',
require_approval TINYINT NOT NULL DEFAULT 0 COMMENT '是否需要审批',
watermark_enabled TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用水印',
sensitive_field_policy VARCHAR(30) NOT NULL DEFAULT 'MASK' COMMENT '敏感字段策略:ALLOW/MASK/DENY',
enabled TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用',
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
PRIMARY KEY (id),
KEY idx_scene_subject (scene_code, subject_type, subject_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='导出权限规则表';
11.12 报表权限规则表 sxb_perm_report_rule
CREATE TABLE sxb_perm_report_rule (
id BIGINT NOT NULL COMMENT '主键ID',
report_code VARCHAR(100) NOT NULL COMMENT '报表编码',
report_name VARCHAR(100) NOT NULL COMMENT '报表名称',
subject_type VARCHAR(30) NOT NULL COMMENT '主体类型:USER/ROLE/POSITION/ORG',
subject_id BIGINT NOT NULL COMMENT '主体ID',
allow_view TINYINT NOT NULL DEFAULT 0 COMMENT '是否允许查看',
allow_export TINYINT NOT NULL DEFAULT 0 COMMENT '是否允许导出',
allow_share TINYINT NOT NULL DEFAULT 0 COMMENT '是否允许分享',
metric_scope JSON DEFAULT NULL COMMENT '允许查看的指标范围',
dimension_scope JSON DEFAULT NULL COMMENT '允许展开的维度范围',
data_scene_code VARCHAR(100) DEFAULT NULL COMMENT '绑定的数据权限场景',
enabled TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用',
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
PRIMARY KEY (id),
KEY idx_report_subject (report_code, subject_type, subject_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报表权限规则表';
11.13 审计日志表 sxb_perm_audit_log
CREATE TABLE sxb_perm_audit_log (
id BIGINT NOT NULL COMMENT '主键ID',
tenant_id BIGINT DEFAULT NULL COMMENT '租户ID',
user_id BIGINT DEFAULT NULL COMMENT '用户ID',
scene_code VARCHAR(100) DEFAULT NULL COMMENT '场景编码',
resource_code VARCHAR(100) DEFAULT NULL COMMENT '资源编码',
policy_code VARCHAR(100) DEFAULT NULL COMMENT '策略编码',
mapper_id VARCHAR(255) DEFAULT NULL COMMENT 'Mapper方法',
original_sql LONGTEXT DEFAULT NULL COMMENT '原始SQL',
final_sql LONGTEXT DEFAULT NULL COMMENT '改写后SQL',
hit_rules VARCHAR(1000) DEFAULT NULL COMMENT '命中规则',
execute_result VARCHAR(30) DEFAULT NULL COMMENT '执行结果:PASS/DENY/SKIP/ERROR',
deny_reason VARCHAR(1000) DEFAULT NULL COMMENT '拒绝原因',
error_message VARCHAR(1000) DEFAULT NULL COMMENT '错误信息',
request_ip VARCHAR(50) DEFAULT NULL COMMENT '请求IP',
terminal_type VARCHAR(30) DEFAULT NULL COMMENT '终端类型',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (id),
KEY idx_user_scene_time (user_id, scene_code, create_time),
KEY idx_tenant_time (tenant_id, create_time),
KEY idx_result_time (execute_result, create_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限审计日志表';
11.14 越权告警表 sxb_perm_security_alert
CREATE TABLE sxb_perm_security_alert (
id BIGINT NOT NULL COMMENT '主键ID',
tenant_id BIGINT DEFAULT NULL COMMENT '租户ID',
user_id BIGINT DEFAULT NULL COMMENT '用户ID',
alert_type VARCHAR(50) NOT NULL COMMENT '告警类型',
alert_level VARCHAR(20) NOT NULL COMMENT '告警级别:LOW/MIDDLE/HIGH/CRITICAL',
scene_code VARCHAR(100) DEFAULT NULL COMMENT '场景编码',
resource_code VARCHAR(100) DEFAULT NULL COMMENT '资源编码',
request_path VARCHAR(255) DEFAULT NULL COMMENT '请求路径',
request_ip VARCHAR(50) DEFAULT NULL COMMENT '请求IP',
terminal_type VARCHAR(30) DEFAULT NULL COMMENT '终端类型',
alert_message VARCHAR(1000) DEFAULT NULL COMMENT '告警信息',
handle_status VARCHAR(30) NOT NULL DEFAULT 'PENDING' COMMENT '处理状态:PENDING/HANDLED/IGNORED',
handle_user_id BIGINT DEFAULT NULL COMMENT '处理人',
handle_time DATETIME DEFAULT NULL COMMENT '处理时间',
handle_remark VARCHAR(500) DEFAULT NULL COMMENT '处理备注',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (id),
KEY idx_tenant_time (tenant_id, create_time),
KEY idx_user_time (user_id, create_time),
KEY idx_alert_level (alert_level, handle_status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限越权告警表';
11.15 权限缓存刷新事件表 sxb_perm_cache_event
CREATE TABLE sxb_perm_cache_event (
id BIGINT NOT NULL COMMENT '主键ID',
tenant_id BIGINT DEFAULT NULL COMMENT '租户ID',
event_type VARCHAR(50) NOT NULL COMMENT '事件类型:USER/ROLE/SCENE/POLICY/FIELD/EXPORT/REPORT/ALL',
target_id BIGINT DEFAULT NULL COMMENT '目标ID',
scene_code VARCHAR(100) DEFAULT NULL COMMENT '场景编码',
event_payload JSON DEFAULT NULL COMMENT '事件内容',
publish_status VARCHAR(30) NOT NULL DEFAULT 'PENDING' COMMENT '发布状态:PENDING/PUBLISHED/FAILED',
operator_id BIGINT DEFAULT NULL COMMENT '操作人',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (id),
KEY idx_event_status (event_type, publish_status),
KEY idx_tenant_time (tenant_id, create_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限缓存刷新事件表';
12. Java 工程结构与核心接口设计
12.1 推荐工程结构
sxb-permission-platform
├── annotation
│ ├── PermissionScene.java
│ ├── DataPermission.java
│ ├── FieldPermission.java
│ ├── ExportPermission.java
│ ├── ReportPermission.java
│ └── PermissionIgnore.java
├── context
│ ├── PermissionContext.java
│ ├── PermissionContextHolder.java
│ └── PermissionContextFactory.java
├── engine
│ ├── PermissionPlatformFacade.java
│ ├── DataPermissionEngine.java
│ ├── FieldPermissionEngine.java
│ ├── ExportPermissionEngine.java
│ ├── ReportPermissionEngine.java
│ ├── MaskingEngine.java
│ └── SecurityAlertEngine.java
├── interceptor
│ └── DataPermissionInnerInterceptor.java
├── parser
│ ├── DataPermissionSqlParser.java
│ └── JsqlParserDataPermissionSqlParser.java
├── cache
│ ├── PermissionCacheService.java
│ └── PermissionCacheRefreshListener.java
├── audit
│ ├── PermissionAuditService.java
│ └── PermissionAlertService.java
├── entity / mapper / service / controller
└── config
└── PermissionPlatformAutoConfiguration.java
12.2 统一权限上下文
public class PermissionContext {
private Long userId;
private Long tenantId;
private Long companyId;
private Long orgId;
private Long shopId;
private Long warehouseId;
private Long employeeId;
private List<Long> roleIds;
private List<Long> positionIds;
private String terminalType;
private String loginType;
private String sceneCode;
private String resourceCode;
private String requestPath;
private Boolean superAdmin;
private Boolean tenantAdmin;
}
12.3 权限平台门面接口
public interface PermissionPlatformFacade {
boolean checkMenu(PermissionContext context, String menuCode);
boolean checkButton(PermissionContext context, String buttonCode);
DataPermissionResult resolveDataPermission(PermissionContext context);
FieldPermissionResult resolveFieldPermission(PermissionContext context);
ExportPermissionResult checkExportPermission(PermissionContext context);
ReportPermissionResult checkReportPermission(PermissionContext context);
}
12.4 注解设计
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PermissionScene {
String value();
String resource() default "";
String type() default "QUERY";
}
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataPermission {
String scene() default "";
String table() default "";
String alias() default "";
boolean required() default true;
}
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldPermission {
String scene() default "";
String table() default "";
boolean maskEnabled() default true;
}
13. MyBatis-Plus 拦截器与 SQL 改写设计
13.1 拦截器职责
- 获取当前 MappedStatement 和 BoundSql。
- 识别当前 Mapper 方法是否需要数据权限。
- 从注解、参数、上下文中解析 scene_code。
- 构造 PermissionContext。
- 调用 DataPermissionEngine 解析规则并生成条件。
- 通过 JSQLParser 解析 SQL,识别主表、别名、WHERE、JOIN、子查询。
- 将权限条件追加到 WHERE 中。
- 写入审计日志。
13.2 拦截器伪代码
public class DataPermissionInnerInterceptor implements InnerInterceptor {
@Override
public void beforeQuery(Executor executor,
MappedStatement ms,
Object parameter,
RowBounds rowBounds,
ResultHandler resultHandler,
BoundSql boundSql) {
PermissionContext context = contextFactory.create(ms, parameter);
if (permissionIgnoreResolver.isIgnore(ms)) {
auditService.recordSkip(context, boundSql.getSql(), "IGNORE_ANNOTATION");
return;
}
DataPermissionResult result = dataPermissionEngine.resolve(context);
if (!Boolean.TRUE.equals(result.getAllowed())) {
alertService.alertDenyAccess(context, result.getDenyReason());
throw new AccessDeniedException(result.getDenyReason());
}
String finalSql = sqlParser.appendCondition(boundSql.getSql(), result.getSqlCondition());
PluginUtils.mpBoundSql(boundSql).sql(finalSql);
auditService.recordHit(context, boundSql.getSql(), finalSql, result);
}
}
13.3 拦截器顺序建议
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 先做数据权限 SQL 改写
interceptor.addInnerInterceptor(new DataPermissionInnerInterceptor());
// 再做分页
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
建议:数据权限拦截器放在分页拦截器之前,确保 count SQL 和分页 SQL 都基于权限范围生成。
14. 缓存与权限变更刷新机制
14.1 缓存结构
Caffeine 本地缓存
↓ 未命中
Redis 分布式缓存
↓ 未命中
MySQL 权限配置表
14.2 缓存 Key 规范
sxb:perm:menu:{tenantId}:{userId}
sxb:perm:button:{tenantId}:{userId}
sxb:perm:scene:{tenantId}:{userId}:{sceneCode}
sxb:perm:data:{tenantId}:{userId}:{sceneCode}
sxb:perm:field:{tenantId}:{userId}:{sceneCode}
sxb:perm:export:{tenantId}:{userId}:{sceneCode}
sxb:perm:report:{tenantId}:{userId}:{reportCode}
sxb:perm:mask-rule:{maskRuleCode}
sxb:perm:table-mapping:{tableName}
14.3 权限变更刷新流程
管理员修改权限配置
↓
写入数据库
↓
写入 sxb_perm_cache_event
↓
发布 Redis Topic: sxb:perm:cache-refresh
↓
各服务节点收到消息
↓
删除 Caffeine 本地缓存
↓
删除 Redis 分布式缓存
↓
下次访问重新加载权限配置
15. 管理后台功能设计
15.1 权限平台菜单结构
系统设置
└── 权限平台
├── 权限资源管理
├── 菜单权限管理
├── 按钮权限管理
├── 场景权限管理
├── 数据权限策略
├── 数据权限规则
├── 表字段映射管理
├── 用户数据授权
├── 字段权限规则
├── 脱敏规则管理
├── 导出权限管理
├── 报表权限管理
├── 权限审计日志
└── 越权告警中心
15.2 页面功能说明
|
页面 |
核心功能 |
|
权限资源管理 |
维护菜单、按钮、API、字段、报表、导出、打印、分享等资源。 |
|
场景权限管理 |
维护 scene_code、请求路径、终端、资源、默认模式。 |
|
数据权限策略 |
维护策略名称、优先级、组合方式、启用状态。 |
|
数据权限规则 |
维护维度、范围、字段、操作符、值来源、自定义 SQL。 |
|
表字段映射管理 |
维护业务表与权限维度字段的关系。 |
|
用户数据授权 |
给用户、角色、岗位授权门店、仓库、客户、供应商、货主等数据范围。 |
|
字段权限规则 |
维护字段可见、隐藏、只读、可编辑、脱敏规则。 |
|
导出权限管理 |
维护导出开关、最大行数、频率、审批、水印、敏感字段策略。 |
|
报表权限管理 |
维护报表访问、指标、维度、导出、分享。 |
|
越权告警中心 |
查看、处理、关闭权限风险告警。 |
15.3 用户数据授权页面建议
左侧:用户 / 角色 / 岗位 / 组织树
右侧:授权维度 Tabs
├── 门店权限
├── 仓库权限
├── 客户权限
├── 供应商权限
├── 货主权限
├── 商品分类权限
├── 财务组织权限
└── 报表权限
支持:批量授权、复制授权、按角色授权、按岗位授权、过期时间、授权来源、变更日志。
16. 升鲜宝业务模块接入清单
|
模块 |
接入重点 |
|
PMS 商品 |
商品、分类、品牌、单位、SKU、销售范围、采购范围、成本字段权限。 |
|
CRM 客户 |
客户数据权限、业务员客户权限、手机号/地址脱敏、账期/授信字段权限。 |
|
SUP 供应商 |
供应商数据权限、联系人脱敏、采购价字段权限。 |
|
OMS 订单 |
订单数据权限、门店/客户/业务员范围、金额/毛利字段权限、导出权限。 |
|
PUR 采购 |
采购员、供应商、采购订单、采购价字段权限。 |
|
WMS 仓库 |
仓库权限、库位权限、库存成本权限、出入库单权限。 |
|
HWMS 门店仓 |
门店库存权限、门店调拨权限、POS 端库存权限。 |
|
POS 收银 |
门店商品权限、会员手机号脱敏、收银数据权限。 |
|
COST 成本 |
成本价、移动加权、FIFO、标准成本字段权限。 |
|
FIN 财务 |
应收、应付、利润、账本、结算组织权限。 |
|
REPORT 报表 |
报表访问、指标、维度、导出、分享权限。 |
|
EXPORT 导出中心 |
导出审批、水印、敏感字段控制、导出审计。 |
16.1 典型角色数据范围
|
角色 |
默认数据范围 |
敏感字段策略 |
|
老板 |
当前公司全部数据 |
可看成本、毛利、利润 |
|
店长 |
当前门店数据 |
不看成本和毛利,可看销售额 |
|
业务员 |
本人负责客户数据 |
客户手机号脱敏,不看成本 |
|
仓管员 |
授权仓库数据 |
不看销售毛利,可看库存数量 |
|
采购员 |
授权供应商/采购组织 |
可看采购价,不看销售毛利 |
|
财务 |
授权结算组织 |
可看应收应付、成本、利润 |
|
供应商 |
自己供应商主体相关数据 |
只能看自己的采购订单和对账 |
|
客户 |
自己客户主体相关数据 |
只能看自己的订单、账单、分享码 |
17. 场景编码规范与初始化建议
17.1 编码规则
基础格式:模块:业务对象:动作
扩展格式:模块:业务对象:动作:扩展场景
模块示例:
pms 商品域
crm 客户域
sup 供应商域
oms 订单域
pur 采购域
wms 公司仓库域
hwms 门店仓库域
pos 收银域
cost 成本域
fin 财务域
report 报表域
export 导出中心
17.2 初始化场景清单
|
场景编码 |
场景名称 |
类型 |
|
pms:goods:manage:list |
商品管理列表 |
QUERY |
|
pms:goods:manage:detail |
商品详情 |
DETAIL |
|
oms:sale-order:select-goods |
销售开单选择商品 |
SELECT |
|
pur:purchase-order:select-goods |
采购开单选择商品 |
SELECT |
|
pos:cashier:select-goods |
POS收银选择商品 |
SELECT |
|
crm:customer:list |
客户列表 |
QUERY |
|
crm:customer:export |
客户导出 |
EXPORT |
|
sup:supplier:list |
供应商列表 |
QUERY |
|
oms:sale-order:list |
销售订单列表 |
QUERY |
|
oms:sale-order:export |
销售订单导出 |
EXPORT |
|
wms:stockin:list |
入库单列表 |
QUERY |
|
wms:stockout:list |
出库单列表 |
QUERY |
|
wms:inventory:list |
库存查询 |
QUERY |
|
report:boss-dashboard:view |
老板驾驶舱 |
REPORT |
|
report:sale-summary:view |
销售汇总报表 |
REPORT |
|
fin:receivable:list |
应收列表 |
QUERY |
|
fin:payable:list |
应付列表 |
QUERY |
18. 迁移实施路线
|
阶段 |
工作内容 |
|
第一阶段:统一权限底座 |
建设权限上下文、场景编码、数据权限表、SQL拦截器、审计日志。优先接入商品、客户、供应商、销售订单、采购订单、库存单据。 |
|
第二阶段:多表 JOIN 与场景治理 |
补充表字段映射、表别名识别、JOIN 查询改写、QueryFacade 场景传递、导出场景独立。 |
|
第三阶段:用户数据授权中心 |
建设用户/角色/岗位的数据授权页面,支持门店、仓库、客户、供应商、货主、财务组织授权。 |
|
第四阶段:字段权限与脱敏 |
接入客户、供应商、订单、成本、财务、报表敏感字段控制。 |
|
第五阶段:导出权限与导出中心 |
统一导出任务、行数限制、频率限制、审批、水印、导出审计。 |
|
第六阶段:报表权限 |
接入老板驾驶舱、销售汇总、库存成本、客户对账、供应商对账、利润报表。 |
|
第七阶段:越权告警中心 |
接入风险识别、告警处理闭环、权限治理报表。 |
18.1 重构建议
- 先不要一次性改完所有业务 SQL,优先接入高风险模块:订单、客户、供应商、库存、财务、导出。
- 保留旧 SQL 中已有的租户条件,但逐步迁移到统一拦截器,避免重复条件影响性能。
- 新增接口必须强制声明 scene_code。旧接口可通过 URL 映射兜底。
- 对导出、报表、分享码查看这类高风险入口,必须优先独立配置场景权限。
- 每个阶段都要配合审计日志观察命中规则,防止误拦截或漏拦截。
19. 测试验收清单
|
测试项 |
验收标准 |
|
租户隔离 |
任何普通查询、导出、报表都不能跨 tenant_id 返回数据。 |
|
门店权限 |
店长只能看到当前门店或授权门店数据。 |
|
仓库权限 |
仓管员只能看到授权仓库单据和库存。 |
|
客户权限 |
业务员只能看到本人负责或授权客户。 |
|
供应商端 |
供应商只能看到自己供应商主体的数据。 |
|
客户侧 |
客户只能看到自己的订单、账单和分享数据。 |
|
字段权限 |
不同角色返回字段符合可见、隐藏、脱敏规则。 |
|
导出权限 |
导出行数、频率、字段、水印、审批规则生效。 |
|
报表权限 |
报表指标、维度、数据范围符合规则。 |
|
SQL解析 |
单表、JOIN、子查询、分页 count SQL 均能正确追加权限。 |
|
默认拒绝 |
未配置场景或策略时拒绝访问并记录日志。 |
|
审计告警 |
拒绝访问、SQL解析失败、跨租户风险、导出风险能生成告警。 |
|
缓存刷新 |
权限变更后各服务节点权限缓存能及时失效。 |
20. 风险控制与最佳实践
20.1 风险点
|
风险 |
控制措施 |
|
SQL 太复杂无法解析 |
配置 sql-parse-fail-mode=deny;复杂查询单独写安全 Resolver。 |
|
别名识别失败 |
通过 @DataPermissionAlias 或表字段映射显式声明主表别名。 |
|
权限条件重复 |
迁移期允许重复,但后续逐步清理业务 SQL 中的硬编码权限条件。 |
|
导出数据泄露 |
导出场景独立、字段白名单、敏感字段脱敏、水印、审批、审计。 |
|
字段脱敏遗漏 |
建立敏感字段清单,新增字段必须经过字段敏感级别评审。 |
|
缓存不一致 |
权限修改必须发布缓存刷新事件,并保留短 TTL 兜底。 |
|
超级管理员滥用 |
超级管理员访问敏感报表、导出敏感数据也要审计和告警。 |
20.2 最佳实践
- 所有业务查询必须有 scene_code;新增接口没有 scene_code 不允许上线。
- 所有导出接口必须使用 EXPORT 类型场景;禁止直接复用列表查询场景。
- 所有报表接口必须使用 REPORT 类型场景;指标权限和维度权限单独配置。
- 所有忽略权限的代码必须写明 reason,并进入审计日志。
- 所有敏感字段必须登记到字段权限规则或敏感字段清单中。
- 权限平台本身的管理操作必须记录操作日志和变更前后内容。
最终落地目标:业务代码专注业务逻辑,权限平台统一负责安全边界。
附录 A. 枚举规范
A.1 SceneTypeEnum
QUERY 普通查询
DETAIL 详情查看
SELECT 下拉选择 / 业务选择器
EXPORT 导出
REPORT 报表
PRINT 打印
SHARE 分享码查看
IMPORT 导入
ACTION 业务动作
A.2 DataScopeTypeEnum
ALL
CURRENT_TENANT
CURRENT_COMPANY
CURRENT_ORG
CURRENT_ORG_AND_CHILDREN
CURRENT_SHOP
ASSIGNED_SHOPS
CURRENT_WAREHOUSE
ASSIGNED_WAREHOUSES
CREATED_BY_SELF
SALESMAN_SELF
ASSIGNED_CUSTOMERS
ASSIGNED_SUPPLIERS
ASSIGNED_OWNERS
CUSTOM_SAFE_SQL
NONE
A.3 FieldPermissionTypeEnum
VISIBLE
HIDDEN
READONLY
EDITABLE
MASK
A.4 AlertLevelEnum
LOW
MIDDLE
HIGH
CRITICAL
附录 B. 配置文件示例
sxb:
permission:
enabled: true
default-mode: deny
sql-parse-fail-mode: deny
audit-enabled: true
record-sql: true
super-admin-bypass: true
caffeine-enabled: true
redis-enabled: true
field-permission-enabled: true
masking-enabled: true
export-permission-enabled: true
report-permission-enabled: true
alert-enabled: true
ignore-mapper-patterns:
- "*.selectDict*"
- "*.selectConfig*"
ignore-tables:
- sys_dict
- sys_config
- sys_area
附录 C. 典型业务接入代码示例
C.1 销售订单列表
@PermissionScene(value = "oms:sale-order:list", type = "QUERY")
@DataPermission(scene = "oms:sale-order:list", table = "oms_order", alias = "o")
@FieldPermission(scene = "oms:sale-order:list", table = "oms_order")
@GetMapping("/page")
public Result<PageVO<SaleOrderVO>> page(SaleOrderQuery query) {
return saleOrderService.page(query);
}
C.2 销售订单导出
@PermissionScene(value = "oms:sale-order:export", type = "EXPORT")
@DataPermission(scene = "oms:sale-order:export", table = "oms_order", alias = "o")
@FieldPermission(scene = "oms:sale-order:export", table = "oms_order")
@ExportPermission(scene = "oms:sale-order:export", exportName = "销售订单导出")
@PostMapping("/export")
public Result<Long> export(@RequestBody SaleOrderExportQuery query) {
return exportService.createExportTask(query);
}
C.3 老板驾驶舱报表
@PermissionScene(value = "report:boss-dashboard:view", type = "REPORT")
@ReportPermission(reportCode = "boss_dashboard", scene = "report:boss-dashboard:view")
@GetMapping("/boss-dashboard")
public Result<BossDashboardVO> bossDashboard(ReportQuery query) {
return reportService.getBossDashboard(query);
}
文档结论
升鲜宝统一权限平台化组件建议按“统一身份上下文 + 统一场景编码 + 统一资源模型 + 数据权限引擎 + 字段权限引擎 + 导出权限引擎 + 报表权限引擎 + 脱敏引擎 + 审计告警中心 + 缓存刷新机制”的方式建设。
这套方案能够支撑升鲜宝后续的 SaaS 多租户、门店协同、供应商协同、客户协同、老板报表、财务报表、导出中心、打印中心、分享码查看等高安全要求业务。
最终原则:业务模块只声明场景,权限平台统一负责安全边界。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)