外观
当前用户查询
引入 springboot-business-system-menu-controller-app 后,用户以已有登录会话查询自己的角色和菜单权限。所有入口都从 SessionUserUtil 取得 userId() 与 client(),不接受请求体指定其他用户或客户端。依赖和认证前提见快速开始,响应及 ID 约定见菜单管理。
选择查询入口
以下请求全部为 GET,无请求体。
| 路径 | data 类型 | 实际范围 |
|---|---|---|
/api/app/system/role/self | SystemRoleMapVo[] | 当前用户绑定且 clientId 匹配会话客户端的角色,不过滤禁用状态 |
/api/app/system/role/permission/self | SystemRolePermissionMapVo[] | 上述客户端角色关联的原始权限明细,不按菜单启用/显示状态过滤 |
/api/app/system/menu/all | SystemMenuMapVo[] | 当前客户端全部未禁用菜单,附上当前用户聚合权限,未授权菜单也会返回 |
/api/app/system/menu/tree | TreeNode<SystemMenuMapVo>[] | 同样的菜单来源,先组树再执行现有递归处理;不保证剔除无权限节点 |
用户没有绑定角色时,角色和权限接口返回空列表;只要客户端仍有可用菜单,菜单接口就不保证返回空列表。self 权限接口按角色客户端过滤,并没有校验关联菜单客户端,异常的跨客户端授权仍可能出现在原始明细中。
读取角色与原始授权
角色字段为 id、name、clientId、isDisable。权限明细字段为 id、roleId、menuId、permission,其中 id 是关系记录 ID,不是菜单 ID。
权限明细保留每个角色的原始记录,不按菜单合并,不归一化字符串。多个角色可以分别对同一菜单授权,因此前端若直接使用此接口,需要自行按 menuId 合并。
菜单接口已经完成聚合:把同一菜单在各角色中的权限用逗号拼接,移除普通空格和换行、过滤空项、去重并排序。未授权菜单的 permission 为 ""。角色权限记录的 permission 若为 null,当前聚合可能失败,写入时应保存有效字符串或删除该授权记录。
展示菜单与树
菜单业务字段见菜单表单和字段。App 响应中的 permission 是用户实际聚合权限,替换了菜单本身的操作声明;管理端菜单响应则保留菜单原始 permission。
树节点使用 item 包装菜单,示例只展示相关字段:
json
{
"item": {
"id": "10001",
"title": "演示报表",
"parentId": null,
"clientId": "web",
"isDisable": 0,
"isShow": 1,
"sortOrder": 10,
"permission": "查询"
},
"children": null
}App 菜单查询仅限制 isDisable=0,不限制 isShow。隐藏菜单仍可能返回并具备操作权限,前端按自身展示规则处理 isShow。两种菜单接口均未按 sortOrder 排序,需要界面自行排序。
组树时,父节点不在当前集合中的菜单会成为根节点。因此禁用父菜单不会递归禁用其后代;后代未被禁用时仍可能以根节点返回。
树接口的当前限制
当前递归逻辑对无权限节点执行的是清空 children,并未从父列表或根列表删除节点;同层发现首个有权限分支后还会提前返回。因此不能把返回的树视为已经完整按权限裁剪。
需要“只展示有权限节点及其祖先”的界面,可从 /all 的完整平铺数据构造树,自底向上保留自身权限非空或有可见后代的节点,再依据显示状态和排序值渲染。若菜单元数据本身不能向未授权用户暴露,应在应用服务端提供过滤后的查询接口,前端裁剪只控制展示。
菜单查询不是接口授权结果。实际操作由认证组件按模块与操作权限判断;角色禁用、跨客户端关系以及缓存时序的限制见角色与授权。
排查查询结果
| 现象 | 核对内容 |
|---|---|
| 角色接口没有目标角色 | 当前用户是否绑定该角色,角色 clientId 是否等于会话 client(),角色是否已逻辑删除 |
| 原始权限存在,菜单列表没有对应菜单 | 菜单是否属于当前客户端、是否已禁用或逻辑删除 |
| 菜单存在但权限为空 | 角色是否存在该菜单 ID 的权限记录,是否授予非空操作字符串 |
| 隐藏菜单仍出现 | isShow 不参与 App 服务端过滤 |
| 禁用角色后权限仍在 | 当前角色与操作权限查询未过滤角色禁用状态,需解绑或移除授权 |
| 菜单列表已变化,接口权限仍旧 | 检查写入入口是否刷新缓存、是否在事务提交后刷新,以及各实例 Store 是否共享 |
这些接口不接收工作空间条件,不根据当前工作空间成员角色调整菜单。空间成员授权属于独立业务域,见成员与角色。