本文档说明 MES 项目中 EOS 原生权限体系与 MES Web RBAC 的关系,以及角色、菜单数据分别存储在哪里、如何保存关联。
2026-07-31 更新:按当前代码实现修订。eosrole 已映射并读写 **
STPermission**(菜单「执行」+ ERP 对象操作)与 **STUserGroup**(用户-角色);MES Web 按钮权限写入 **sys_role_menu**。核心授权表仍为 **mesdata.dbo.STPermission**。
关联文档:EOS 菜单树 NodeID 与 ObjectID 说明
结论摘要
**在本项目(mes-parent)中,EOS 角色 ↔ 菜单授权可由 MES eosrole「配置菜单权限」写入 STPermission**;也可在 EOS 原生安全管理器中配置。用户 ↔ 角色由 eosrole「配置用户权限」双写 STUserGroup + sys_user_role。
| 能力 | 库 | 表 | MES 是否实现 |
|---|---|---|---|
| EOS 用户/角色 | mesdata | STUsers(uGroup=0/1) |
角色 CRUD(eosrole) |
| 用户 ↔ 角色 | mesdata | STUserGroup |
已映射,由 EosRoleUserServiceImpl 管理(双写 sys_user_role) |
| 角色 ↔ 菜单 | mesdata | STPermission |
已映射,由 EosRolePermissionServiceImpl / EosRoleObjectPermissionServiceImpl 读写 |
| EOS 菜单树 | messys | Tree + ObjectRegister |
eostree 维护/同步 |
| EOS 角色 → MES 角色 | mesdata | sys_role(eos_role_id) |
同步元数据;权限保存时也可自动 syncRole |
| MES 角色 → MES 菜单/按钮 | mesdata | sys_role_menu |
角色管理页面;eosrole 保存 MES 按钮时亦写入 |
| EOS NodeID → MES menu_id | mesdata | sys_menu_eos_node |
sync/backfill/copy 写入 |
EOS 原生权限生效链路:
1 | STUsers(用户,uGroup=0) |
1. EOS 侧数据模型
1.1 用户与角色:STUsers(mesdata)
角色与用户共用 mesdata.dbo.STUsers,通过 uGroup 区分:
| uGroup | 含义 |
|---|---|
| 0 | 用户 |
| 1 | 角色 |
相关代码:StusersEntity、StusersServiceImpl.saveRole / updateRole、EosRoleController(路径 /eosrole)。
eosrole 页面「保存角色」只写角色基本信息(编码、名称、描述、分组 Categories、启用状态),不涉及菜单勾选。菜单与对象操作权限在「配置菜单权限」弹窗中单独保存(见 §2.3);用户分配在「配置用户权限」中保存(见 §2.5)。
EmpowermentRight、RelateUserH 等字段在 MES 新增角色时仅填默认值,不用于菜单授权;菜单授权走 STPermission。
1.2 用户-角色:STUserGroup(mesdata)
| 字段 | 含义 |
|---|---|
UserID |
用户 OID(STUsers.OID,uGroup=0) |
GroupID |
角色 OID(STUsers.OID,uGroup=1) |
Back |
备注 |
MES 已映射:StUserGroupEntity + EosRoleUserServiceImpl。eosrole「配置用户权限」保存时:
- 清空该角色在
STUserGroup中的旧关联,再批量插入新用户 - 按
STUsers.UserID↔sys_user.username匹配 MES 用户;有 MES 用户时先ensureMesRole,再全量改写sys_user_role
也可在 EOS 原生安全管理中分配角色(同样写入 STUserGroup)。
1.3 菜单:Tree + ObjectRegister(messys)
| 表 | 库 | 作用 |
|---|---|---|
Tree |
messys | EOS Web 菜单树(NodeID、ParentID、NodeCaption、Functions 等) |
ObjectRegister |
messys | 对象注册;OwnerID = Tree.NodeID,TypeID = 7 表示菜单/目录 |
UniqueNO |
messys | 分配 Tree 的 NodeID(NName='tree') |
新增菜单节点时(TreeServiceImpl.addNode)会:
- 从
UniqueNO分配新NodeID - 写入
Tree - 写入
ObjectRegister,并将返回的ObjectID回填到Tree.ObjectID
从 MES 同步菜单时(TreeServiceImpl.syncFromSysMenu),同样会为每个节点创建 ObjectRegister 记录。
数据库 schema 配置见 mes-web/src/main/resources/schema.properties:
1 | eossys.schema=messys.dbo |
1.4 角色-菜单关联:STPermission(mesdata)
核心授权表。EOS 原生安全管理器与 MES eosrole「配置菜单权限」保存时均写入此表。
| 字段 | 类型 | 含义 |
|---|---|---|
UserID |
int | STUsers.OID;绝大多数为角色(uGroup=1),少量为用户直授(uGroup=0) |
ObjectID |
int | messys.dbo.ObjectRegister.ObjectID |
Oprate |
nvarchar | 操作类型(见下表) |
Permission |
int | 权限值;含义随 Oprate 类型不同(见下表) |
ERP 模式下 Permission 双语义(本环境 WebPermission 未启用,按钮授权均走 STPermission):
| Oprate 类型 | 示例 | Permission | 含义 |
|---|---|---|---|
| 菜单 | 执行 |
1 | 允许可见(白名单;无记录=不可见) |
| 按钮/操作 | 增加、EX61:组织架构分发 |
0 | 禁用(黑名单;无记录=允许) |
常见 Oprate 取值:执行(菜单);标准操作(增加、修改、删除、审核…);自定义 EX{ExFunction.ID}:{SDesc}(如 EX61:组织架构分发)。
菜单授权路径:
1 | STPermission(ObjectID, Oprate='执行', Permission=1) |
MES 读写实现:
| 服务 | 职责 |
|---|---|
EosRolePermissionServiceImpl |
查询/保存菜单「执行」(objectIds + mode) |
EosRoleObjectPermissionServiceImpl |
ERP 对象操作(operationPermissions)+ MES 按钮(sys_role_menu) |
queryMenuObjectIds 过滤条件:Oprate=执行 且 Permission=1(当前未按 ObjectRegister.TypeID=7 过滤)。
1.5 ERP 按钮权限(ExFunction + DjDy)
| 层级 | 粒度 | 存储 |
|---|---|---|
| 按钮定义 | 每个 ExFunction 一条 | messys.ExFunction(Note1 like 'button%') |
| 授权 ObjectID | 每个单据(DjDy)一个 | ObjectRegister.Object = DjDy.DjCName 且 TypeID != 7(OwnerID 可为 null) |
| 授权 Oprate | 每个按钮一个 | EX{ID}:{SDesc};同一 ObjectID 多行 = 同单据多按钮 |
链路:
1 | Tree.Functions(如 单据(组织架构)) |
复合单据示例(Tree NodeID=430):
| 用途 | ObjectID | TypeID | 说明 |
|---|---|---|---|
| 菜单「执行」 | 468 | 7 | OwnerID=430,名「组织机构关系表」 |
| 按钮 EX61 | 965 | 1 | OwnerID=null,名「组织架构」,与菜单 ObjectID 不同 |
同一 DjDm 下多个 ExFunction(如 DjDm=212 的 EX13/EX14/EX16/EX17)共用同一业务 ObjectID,以不同 Oprate 区分。
业务 ObjectID 解析见 EOS 菜单树 NodeID 与 ObjectID 说明 §5.1(EosMenuObjectResolver)。
说明:WebPermission 本环境未启用;SType=CX 且安全管理器不可见的 STPermission 记录(如 EX10:查看JSON)视为历史垃圾数据。
当前环境数据量(仅供参考):
| 表 | 记录数 | 说明 |
|---|---|---|
STPermission |
~1625 | 主路径(角色 ~1595,用户直授 ~30) |
WebPermission |
0 | Web 对象权限(RoleID + ObjID),本环境未使用 |
STDomainPermission |
0 | 域-菜单节点(DomainID + MenuNodeID),本环境未使用 |
1.6 跨库关系图
1 | ┌──────────────────────── mesdata ────────────────────────┐ |
2. MES 侧数据模型
2.1 角色-菜单:sys_role_menu
MES Web「角色管理」(role.html + role.js)通过 zTree 勾选菜单,提交 menuIdList 到 /sys/role/save 或 /sys/role/update。
保存逻辑(SysRoleMenuServiceImpl.saveOrUpdate):
- 按
role_id删除原有关联 - 批量插入新的
(role_id, menu_id)记录
权限生效链路:
1 | sys_user → sys_user_role → sys_role → sys_role_menu → sys_menu |
eosrole 保存 MES 菜单/按钮时也会写入同一张表(见 §2.3)。
2.2 EOS 角色同步到 MES
EosRoleSyncServiceImpl / 定时任务 EosTask.sycnEosRole() 调用:
sysRoleService.saveWithoutMenu()— 新建 MES 角色sysRoleService.updateWithoutMenu()— 更新 MES 角色
同步字段:角色名、描述、分组、eos_role_id。定时/手动同步本身不会同步 EOS STPermission 或 MES sys_role_menu。
若在 eosrole「配置菜单权限」中提交了 mesMenuIds / mesButtonMenuIds,且尚无对应 MES 角色,会自动 syncRole 后再写 sys_role_menu。
2.3 eosrole「配置菜单权限」
eosrole 弹窗支持统一配置:
| 菜单类型 | 识别 | 保存位置 |
|---|---|---|
| ERP 原生 | Functions 不含「函数打开网页」(menuType=erp) |
菜单 → STPermission(Oprate=执行, Permission=1);按钮 → STPermission(EXxx:... 等, Permission=0=禁用) |
| MES Web | Functions 含「函数打开网页」(menuType=mes),sys_menu_eos_node 存 menu_id ↔ eos_node_id |
菜单执行 → STPermission;按钮 → sys_role_menu |
| 目录 | menuType=folder |
通常仅作树结构;勾选子节点时汇总子菜单 objectId |
相关 API(EosRoleController,权限 eosrole:permission):
| 方法 | 路径 | 作用 |
|---|---|---|
| * | /eosrole/menu/tree |
权限菜单树(含 objectId / menuType / sysMenuId) |
| GET | /eosrole/permission/{roleId} |
已授权菜单 objectId(执行+Permission=1) |
| GET | /eosrole/permission/detail/{roleId}?nodeId= |
节点对象/按钮权限详情 |
| GET | /eosrole/permission/mes-menu-ids/{roleId} |
回显 MES 角色全部 sys_role_menu menuId |
| POST | /eosrole/permission/save |
保存菜单执行 + ERP 操作 + MES 按钮 |
| * | /eosrole/menu/backfill-mes-menu-id |
历史 MES 节点回填 sys_menu_eos_node |
POST /eosrole/permission/save body(EosRolePermissionSaveRequest):
| 字段 | 说明 |
|---|---|
roleIds |
EOS 角色 OID 列表 |
objectIds |
勾选菜单的 Tree.ObjectID → STPermission「执行」 |
mode |
append / replace |
mesMenuIds |
MES 目录/菜单 menu_id → sys_role_menu |
mesButtonMenuIds |
MES 按钮 menu_id → sys_role_menu |
operationPermissions |
{objectId, oprate, granted};ERP 禁止列表(granted=false 写 Permission=0) |
operationReplaceObjectIds |
replace 时需清理非「执行」权限的业务 ObjectID |
保存流程:
EosRolePermissionServiceImpl.savePermissions(roleIds, objectIds, mode)— 写菜单「执行」EosRoleObjectPermissionServiceImpl.saveMesAndObjectPermissions(request)— ERP 操作 + MES 按钮
mode=replace 时:先按该角色已有「执行」的 ObjectID 删除这些 ObjectID 下全部 Oprate 行,再插入勾选的「执行」;mesMenuIds 与 mesButtonMenuIds 都为空时不改动 sys_role_menu。
说明:Tree.Functions 里 URL 的 menuId= 是 EOS NodeID(页面跳转用);sys_menu.menu_id 的权威映射在 **mesdata.sys_menu_eos_node**(eos_node_id → menu_id),由 syncFromSysMenu 写入或 backfillSysMenuEosNode 按 URL/NodeDesc 回填。过渡期仍双写 NodeDesc=MES_MENU:{sysMenuId} 作兼容 fallback。
建表与历史迁移脚本:sys_menu_eos_node.sql、sys_menu_eos_node.mysql.sql(位于 mes-security-eos 模块 doc/)。
2.4 MES 菜单管理「设置到 EOS」
MES 菜单管理页(sys/menu)勾选目录/菜单后点击「设置到 EOS」,调用 POST /tree/syncFromSysMenu(menu.js#setToEos)。
| 步骤 | 行为 |
|---|---|
| 1 | 用户选择 EOS 目标目录 parentNodeId |
| 2 | TreeServiceImpl.syncFromSysMenu 为每个 type=0/1 的 sys_menu 新建 EOS Tree 节点 |
| 3 | applySysMenuMapping 写入 sys_menu_eos_node,并双写 NodeDesc=MES_MENU:{sysMenuId}(目录与菜单均写) |
| 4 | type=1 且有 url 时,Functions 生成 MES Web 跳转 URL,其中 menuId= 为新分配的 EOS NodeID |
历史已同步但未写映射的节点,可任选以下方式处理(当前 sync 始终新建节点,不更新旧节点):
| 方式 | 说明 |
|---|---|
| 定时任务 | EosTask.backfillSysMenuEosNode,默认每日 3:00(t_qrtz_schedule_job;升级见 V2__Update_backfill_sys_menu_eos_node_job.sql) |
| 手动接口 | /eosrole/menu/backfill-mes-menu-id |
| 重新同步 | 菜单管理页「设置到 EOS」(会新建节点) |
| SQL 迁移 | 执行 sys_menu_eos_node.sql 从 NodeDesc 导入历史映射 |
定时任务与手动接口共用 TreeService.backfillSysMenuEosNode()。局限:仅对尚无映射记录的节点回填;URL 匹配仅适用于 Functions 含「函数打开网页」的 MES Web 菜单;type=0 目录(Functions 为空)若 NodeDesc 也无映射,需重新「设置到 EOS」。
2.5 eosrole「配置用户权限」
| 方法 | 路径 | 权限 | 作用 |
|---|---|---|---|
| GET | /eosrole/users/assigned/{roleId} |
eosrole:user |
已授权用户(合并 EOS + MES) |
| GET | /eosrole/users/unassigned/{roleId} |
eosrole:user |
待授权用户 |
| POST | /eosrole/users/save |
eosrole:user |
双写 STUserGroup + sys_user_role |
3. 两套体系对照
| 维度 | EOS 原生 | MES Web |
|---|---|---|
| 用户/角色表 | mesdata.STUsers |
sys_user / sys_role |
| 用户-角色 | mesdata.STUserGroup |
sys_user_role |
| 菜单表 | messys.Tree + ObjectRegister |
sys_menu |
| 角色-菜单关联 | mesdata.STPermission |
sys_role_menu |
| MES 页面维护 | eosrole(菜单+ERP 对象操作+MES 按钮+用户)/ eostree | 角色管理(含菜单授权) |
| 跨系统同步 | EOS → MES 同步角色元数据;eosrole 保存时可统一写两侧 | 可与 eosrole 统一配置 |
4. 查询 SQL 示例
以下 SQL 在 SQL Server 上验证可用;跨库查询需当前连接对 mesdata、messys 均有读权限。
4.1 查看某角色的菜单权限(含菜单名)
1 | -- @RoleOID: STUsers.OID,且 uGroup = 1 |
4.2 查看某用户通过角色继承的菜单(完整链路)
1 | -- @UserOID: STUsers.OID,且 uGroup = 0 |
4.3 统计各角色的菜单授权数量
1 | SELECT |
4.4 查找拥有某菜单权限的所有角色
1 | -- @MenuNodeID: messys.dbo.Tree.NodeID |
4.5 对比 EOS 角色与 MES 角色(不含菜单)
1 | SELECT |
4.6 检查菜单节点是否已在 ObjectRegister 注册
1 | SELECT |
5. 相关代码路径
| 模块 | 路径 |
|---|---|
| EOS 角色实体 | mes-security-eos/.../entity/StusersEntity.java |
| EOS 角色服务 | mes-security-eos/.../service/impl/StusersServiceImpl.java |
| EOS 角色同步 | mes-security-eos/.../service/impl/EosRoleSyncServiceImpl.java |
| EOS 菜单树 | mes-security-eos/.../service/impl/TreeServiceImpl.java |
| 菜单「执行」权限 | mes-security-eos/.../service/impl/EosRolePermissionServiceImpl.java |
| ERP/MES 对象与按钮 | mes-security-eos/.../service/impl/EosRoleObjectPermissionServiceImpl.java |
| 用户-角色 | mes-security-eos/.../service/impl/EosRoleUserServiceImpl.java |
| 业务 ObjectID 解析 | mes-security-eos/.../support/EosMenuObjectResolver.java |
| 实体 | StPermissionEntity、StUserGroupEntity、TreeEntity、ObjectRegisterEntity |
| 前端 | static/js/modules/security/eosrole.js |
| MES 角色-菜单 | mes-core/.../service/impl/SysRoleMenuServiceImpl.java |
| NodeID ↔ menu_id | sys_menu_eos_node + SysMenuEosNodeService |
| sys_menu → Tree SQL | doc/sql/sys_menu_to_eos_tree.sql |
本环境未使用的 EOS 权限表(可扩展):
| 表 | 说明 |
|---|---|
WebPermission |
Web 对象细粒度权限(RoleID + ObjID + Operate) |
STDomainPermission |
域 ↔ Tree.NodeID |
6. 运维与开发建议
- EOS 客户端菜单权限:可在 EOS 原生安全管理中配置,也可在 MES eosrole「配置菜单权限」中配置;数据均写入
mesdata.dbo.STPermission。运维排查可用上文 SQL。 - MES 页面权限:可在「系统管理 → 角色管理」勾选
sys_menu;也可在 eosrole 中为 MES Web 菜单勾选按钮(写入同一sys_role_menu)。菜单「执行」可见性仍依赖STPermission。 - 两套菜单数据源:
Tree/ObjectRegister:EOS 客户端 / Web 壳菜单sys_menu:MES 页面与 Shiro 权限- eosrole 可在同一弹窗统一配置两侧,但没有从
STPermission自动全量同步到sys_role_menu(或反向)的后台任务;MES 按钮仅在 eosrole 保存时写入。
- 从 EOS 同步角色后:若需在 MES Web 中使用该角色的菜单/按钮,可在角色管理中分配,或在 eosrole 配置菜单权限时一并提交
mesMenuIds/mesButtonMenuIds。 - 跨库注意:
STUsers、STPermission、STUserGroup、sys_*在 mesdata;Tree、ObjectRegister在 messys,关联字段为STPermission.ObjectID↔ObjectRegister.ObjectID。
7. 修订记录
| 日期 | 说明 |
|---|---|
| 2026-06-15 | 初版:基于 mes-parent 代码梳理 EOS / MES 角色菜单关系 |
| 2026-06-16 | eosrole 扩展:ERP 对象操作权限 + MES 按钮权限统一配置 |
| 2026-07-01 | 补充 ERP 按钮权限:STPermission 双语义、ExFunction/DjDy 链路、965/468 复合单据示例;WebPermission 未启用 |
| 2026-07-31 | 按最新实现修订:STPermission/STUserGroup 已映射;统一结论/§5/§6 口径;补 save body(含 operationReplaceObjectIds)、用户权限 API、相关代码路径 |