主题
权限管理接口文档
概述
权限管理模块提供了一单位一平台与子应用之间角色权限和菜单数据的交互能力。一单位一平台向子应用同步用户角色权限变更和角色菜单配置,子应用可向一单位一平台查询用户菜单和角色菜单。权限与角色、菜单关联,实现基于 RBAC(基于角色的访问控制)的权限体系。所有接口遵循国密 SM2/SM4 数字信封加密方案,确保数据传输安全。
交互方向
本模块包含以下交互方向:
| 交互方向 | 接口类型 | 子应用实现要求 | 说明 |
|---|---|---|---|
| 一单位一平台→子应用(推送) | 修改用户角色权限、修改角色菜单 | ✅ 必须实现接收接口 | 一单位一平台主动推送角色权限和菜单变更,子应用需实现对应接收接口 |
| 子应用→一单位一平台(查询) | 查询用户菜单、查询角色菜单 | ❌ 无需实现 | 子应用主动查询菜单数据,一单位一平台提供查询接口 |
重要说明:
- 对于"一单位一平台→子应用"的推送接口,子应用必须实现对应的接收接口
- 对于"子应用→一单位一平台"的查询接口,子应用直接调用一单位一平台提供的接口,无需额外实现
使用场景
- 一单位一平台→子应用(推送): 修改用户角色时,同步用户的角色权限变更
- 一单位一平台→子应用(推送): 修改角色菜单时,同步角色的菜单权限变更
- 子应用→一单位一平台(查询): 子应用向一单位一平台查询用户的菜单
- 子应用→一单位一平台(查询): 子应用向一单位一平台查询角色的菜单
接口设计原则
所有接口均采用国密 SM2/SM4 数字信封加密方案:
- 统一 POST 方式:所有接口使用 POST 方法,业务参数在 encryptData 中加密传输
- 无路径参数:URL 路径中不包含任何业务参数(如 permissionId),所有业务参数均在加密报文中
- 安全性:通过 SM2 混合加密和数字签名确保数据传输的机密性、完整性和不可抵赖性
适用范围
适用于需要角色权限同步和菜单查询的子应用系统。通过本模块的接口,子应用可以实时获取用户的角色权限变更和菜单配置,实现统一的权限管理。
术语定义
核心概念
| 术语 | 说明 |
|---|---|
| 一单位一平台 | 核心管理平台,负责数据存储、权限管理、接口路由等核心功能 |
| 子应用 | 接入一单位一平台的独立业务系统,通过一单位一平台网关与其他系统交互 |
| 网关 | 一单位一平台的统一入口,负责路由转发、身份认证、权限控制、速率限制等 |
操作语义
| 术语 | 说明 | 数据流向 | 接口实现方 |
|---|---|---|---|
| 查询 | 主动请求获取数据 | 子应用→一单位一平台 | 一单位一平台实现 |
| 推送 | 主动通知数据变更 | 一单位一平台→子应用 | 子应用实现接收 |
重要提示:
- "查询"表示子应用主动向一单位一平台请求数据,由一单位一平台提供查询接口
- "推送"表示一单位一平台主动通知子应用数据变更,子应用必须实现对应的接收接口
系统架构
数据流向
查询流程(子应用→一单位一平台)
子应用 → [加密请求] → 一单位一平台 → [加密响应] → 子应用推送流程(一单位一平台→子应用)
一单位一平台 → [加密推送] → 子应用接收接口 → [加密响应] → 一单位一平台重要: 对于推送接口,子应用必须实现接收接口
接口列表
一单位一平台→子应用(推送接口)
| 接口名称 | 请求地址 | 交互方向 | 说明 |
|---|---|---|---|
| 修改用户角色权限 | POST /ydyp/permission/user-role/update | 主→子(推送) | 修改用户的角色权限 |
| 修改角色菜单 | POST /ydyp/permission/role-menu/update | 主→子(推送) | 修改角色的菜单权限 |
⚠️ 重要提示: 以上"主→子(推送)"接口需要子应用实现接收接口,接收一单位一平台推送的角色权限和菜单变更
子应用→一单位一平台(查询接口)
| 接口名称 | 请求地址 | 交互方向 | 说明 |
|---|---|---|---|
| 查询用户菜单 | POST /hztech-application/permission/user/menu | 子→主(查询) | 查询用户的菜单列表 |
| 查询角色菜单 | POST /hztech-application/permission/role/menu | 子→主(查询) | 查询角色的菜单列表 |
注:所有业务参数均在 encryptData 中加密传输,URL 路径中不包含任何业务参数。
接口详情
1.1 修改用户角色权限
⚠️ 子应用需实现此接口
本接口需要子应用实现接收接口,接收一单位一平台推送的用户角色权限变更通知。
实现要求:
- 子应用需在一单位一平台注册接收接口地址
- 接收接口必须验签并解密一单位一平台的推送数据
- 接收接口需返回加密的响应报文
接口信息
| 项目 | 内容 |
|---|---|
| 接口名称 | 修改用户角色权限 |
| 接口code | PERMISSION_USER_ROLE_UPDATE |
| 接口地址 | /ydyp/permission/user-role/update |
| 请求方法 | POST |
| 交互方向 | 一单位一平台 → 子应用 (推送) |
接口描述
修改用户的角色权限。当一单位一平台修改用户的角色时,向子应用同步用户的角色权限变更。此接口会在用户角色发生变化时被调用。
完整时序图
请求参数
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|---|---|---|---|---|
| userId | String | 是 | 用户ID | "USER_001" |
| roleIds | Array | 是 | 角色ID列表 | ["ROLE_001", "ROLE_002"] |
| operation | String | 是 | 操作类型(add/remove/replace) | "replace" |
HTTP 请求示例
http
POST /ydyp/permission/user-role/update HTTP/1.1
Host: subapp.example.com
Content-Type: application/json
{
"appId": "MAIN_SYSTEM",
"version": "1.0",
"timestamp": 1735516800000,
"nonce": "c3d4e5f6-a7b8-9012-cdef-1234567890ab",
"encryptKey": "MIIBOgIBAAJBAKj34GkxFhD90vcNLYLInFEX6...",
"encryptData": "U2FsdGVkX1+jmZn5KqWYEgjPkQKpH5KqWYEg...",
"sign": "MEUCIQDZ5KqWYEgjPkQKpH5KqWYEgjPkQKpH5KqWY..."
}encryptData 解密后的业务数据
json
{
"userId": "USER_001",
"roleIds": ["ROLE_001", "ROLE_002"],
"operation": "replace"
}HTTP 响应示例
json
{
"code": 200,
"message": "success",
"data": {
"userId": "USER_001",
"updateTime": "2026-01-04T00:00:00"
}
}返回值说明
| 字段 | 类型 | 说明 |
|---|---|---|
| code | Integer | 响应状态码,200表示成功 |
| message | String | 响应消息 |
| data.userId | String | 用户ID |
| data.updateTime | String | 更新时间(ISO 8601格式) |
1.2 修改角色菜单
⚠️ 子应用需实现此接口
本接口需要子应用实现接收接口,接收一单位一平台推送的角色菜单权限变更通知。
实现要求:
- 子应用需在一单位一平台注册接收接口地址
- 接收接口必须验签并解密一单位一平台的推送数据
- 接收接口需返回加密的响应报文
接口信息
| 项目 | 内容 |
|---|---|
| 接口名称 | 修改角色菜单 |
| 接口code | PERMISSION_ROLE_MENU_UPDATE |
| 接口地址 | /ydyp/permission/role-menu/update |
| 请求方法 | POST |
| 交互方向 | 一单位一平台 → 子应用 (推送) |
接口描述
修改角色的菜单权限。当一单位一平台修改角色的菜单配置时,向子应用同步角色的菜单权限变更。
完整时序图
请求参数
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|---|---|---|---|---|
| roleId | String | 是 | 角色ID | "ROLE_001" |
| menuIds | Array | 是 | 菜单ID列表 | ["MENU_001", "MENU_002"] |
| operation | String | 是 | 操作类型(add/remove/replace) | "replace" |
HTTP 请求示例
http
POST /ydyp/permission/role-menu/update HTTP/1.1
Host: subapp.example.com
Content-Type: application/json
{
"appId": "MAIN_SYSTEM",
"version": "1.0",
"timestamp": 1735516800000,
"nonce": "c3d4e5f6-a7b8-9012-cdef-1234567890ab",
"encryptKey": "MIIBOgIBAAJBAKj34GkxFhD90vcNLYLInFEX6...",
"encryptData": "U2FsdGVkX1+jmZn5KqWYEgjPkQKpH5KqWYEg...",
"sign": "MEUCIQDZ5KqWYEgjPkQKpH5KqWYEgjPkQKpH5KqWY..."
}encryptData 解密后的业务数据
json
{
"roleId": "ROLE_001",
"menuIds": ["MENU_001", "MENU_002", "MENU_003"],
"operation": "replace"
}HTTP 响应示例
json
{
"code": 200,
"message": "success",
"data": {
"roleId": "ROLE_001",
"updateTime": "2026-01-04T00:00:00"
}
}返回值说明
| 字段 | 类型 | 说明 |
|---|---|---|
| code | Integer | 响应状态码,200表示成功 |
| message | String | 响应消息 |
| data.roleId | String | 角色ID |
| data.updateTime | String | 更新时间(ISO 8601格式) |
2.1 查询用户菜单
接口信息
| 项目 | 内容 |
|---|---|
| 接口名称 | 查询用户菜单 |
| 接口code | PERMISSION_USER_MENU_QUERY |
| 接口地址 | /hztech-application/permission/user/menu |
| 请求方法 | POST |
| 交互方向 | 子应用 → 一单位一平台 (查询) |
接口描述
查询用户的菜单列表。子应用向一单位一平台请求用户的菜单数据,用于前端渲染菜单。
完整时序图
请求参数
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|---|---|---|---|---|
| userId | String | 是 | 用户ID | "USER_001" |
HTTP 请求示例
http
POST /hztech-application/permission/user/menu HTTP/1.1
Host: main.example.com
Content-Type: application/json
{
"appId": "SUB_APP_001",
"version": "1.0",
"timestamp": 1735516800000,
"nonce": "f6a7b8c9-d0e1-1234-5678-9abcdef01234",
"encryptKey": "MIIBOgIBAAJBAKj34GkxFhD90vcNLYLInFEX6...",
"encryptData": "U2FsdGVkX1+jmZn5KqWYEgjPkQKpH5KqWYEg...",
"sign": "MEUCIQDZ5KqWYEgjPkQKpH5KqWYEgjPkQKpH5KqWY..."
}encryptData 解密后的业务数据
json
{
"userId": "USER_001"
}HTTP 响应示例
json
{
"code": 200,
"message": "success",
"data": {
"userId": "USER_001",
"menus": [{
"id": "2008346799554711554",
"parentId": "0",
"code": "app-system",
"name": "应用系统管理",
"alias": "app-system",
"path": "/app-system",
"source": "carbon:apps",
"component": "",
"sort": 1,
"category": 1,
"action": 0,
"isOpen": 1,
"remark": "",
"isDeleted": 0,
"children": [
{
"id": "2008346983223283713",
"parentId": "2008346799554711554",
"code": "app-menu",
"name": "应用菜单管理",
"alias": "app-menu",
"path": "/app-system/app-menu",
"source": "carbon:code-block",
"component": "",
"sort": 1,
"category": 1,
"action": 0,
"isOpen": 1,
"remark": "",
"isDeleted": 0,
"hasChildren": false,
"parentName": "",
"categoryName": "",
"actionName": "",
"isOpenName": ""
}
],
"hasChildren": false,
"parentName": "",
"categoryName": "",
"actionName": "",
"isOpenName": ""
}
]
}
}返回值说明
| 字段 | 类型 | 说明 |
|---|---|---|
| code | Integer | 响应状态码,200表示成功 |
| message | String | 响应消息 |
| data.userId | String | 用户ID |
| data.menus | Array | 菜单列表(树形结构) |
| data.menus[].id | String | 菜单ID |
| data.menus[].parentId | String | 父菜单ID,顶层为"0" |
| data.menus[].code | String | 菜单编码 |
| data.menus[].name | String | 菜单名称 |
| data.menus[].alias | String | 菜单别名 |
| data.menus[].path | String | 路由路径 |
| data.menus[].source | String | 图标标识 |
| data.menus[].component | String | 组件路径 |
| data.menus[].sort | Integer | 排序号 |
| data.menus[].category | Integer | 菜单分类 |
| data.menus[].action | Integer | 操作类型 |
| data.menus[].isOpen | Integer | 是否展开 |
| data.menus[].remark | String | 备注 |
| data.menus[].isDeleted | Integer | 是否删除 |
| data.menus[].children | Array | 子菜单列表 |
2.2 查询角色菜单
接口信息
| 项目 | 内容 |
|---|---|
| 接口名称 | 查询角色菜单 |
| 接口code | PERMISSION_ROLE_MENU_QUERY |
| 接口地址 | /hztech-application/permission/role/menu |
| 请求方法 | POST |
| 交互方向 | 子应用 → 一单位一平台 (查询) |
接口描述
查询角色的菜单列表。子应用向一单位一平台请求角色的菜单数据。
完整时序图
请求参数
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|---|---|---|---|---|
| roleId | String | 是 | 角色ID | "ROLE_001" |
HTTP 请求示例
http
POST /hztech-application/permission/role/menu HTTP/1.1
Host: main.example.com
Content-Type: application/json
{
"appId": "SUB_APP_001",
"version": "1.0",
"timestamp": 1735516800000,
"nonce": "f6a7b8c9-d0e1-1234-5678-9abcdef01234",
"encryptKey": "MIIBOgIBAAJBAKj34GkxFhD90vcNLYLInFEX6...",
"encryptData": "U2FsdGVkX1+jmZn5KqWYEgjPkQKpH5KqWYEg...",
"sign": "MEUCIQDZ5KqWYEgjPkQKpH5KqWYEgjPkQKpH5KqWY..."
}encryptData 解密后的业务数据
json
{
"roleId": "ROLE_001"
}HTTP 响应示例
json
{
"code": 200,
"message": "success",
"data": {
"roleId": "ROLE_001",
"roleName": "系统管理员",
"menus": [
{
"id": "2008346799554711554",
"parentId": "0",
"code": "app-system",
"name": "应用系统管理",
"alias": "app-system",
"path": "/app-system",
"source": "carbon:apps",
"component": "",
"sort": 1,
"category": 1,
"action": 0,
"isOpen": 1,
"remark": "",
"isDeleted": 0,
"children": [
{
"id": "2008346983223283713",
"parentId": "2008346799554711554",
"code": "app-menu",
"name": "应用菜单管理",
"alias": "app-menu",
"path": "/app-system/app-menu",
"source": "carbon:code-block",
"component": "",
"sort": 1,
"category": 1,
"action": 0,
"isOpen": 1,
"remark": "",
"isDeleted": 0,
"hasChildren": false,
"parentName": "",
"categoryName": "",
"actionName": "",
"isOpenName": ""
}
],
"hasChildren": false,
"parentName": "",
"categoryName": "",
"actionName": "",
"isOpenName": ""
}
]
}
}返回值说明
| 字段 | 类型 | 说明 |
|---|---|---|
| code | Integer | 响应状态码,200表示成功 |
| message | String | 响应消息 |
| data.roleId | String | 角色ID |
| data.roleName | String | 角色名称 |
| data.menus | Array | 菜单列表(树形结构) |
| data.menus[].id | String | 菜单ID |
| data.menus[].parentId | String | 父菜单ID,顶层为"0" |
| data.menus[].code | String | 菜单编码 |
| data.menus[].name | String | 菜单名称 |
| data.menus[].alias | String | 菜单别名 |
| data.menus[].path | String | 路由路径 |
| data.menus[].source | String | 图标标识 |
| data.menus[].component | String | 组件路径 |
| data.menus[].sort | Integer | 排序号 |
| data.menus[].category | Integer | 菜单分类 |
| data.menus[].action | Integer | 操作类型 |
| data.menus[].isOpen | Integer | 是否展开 |
| data.menus[].remark | String | 备注 |
| data.menus[].isDeleted | Integer | 是否删除 |
| data.menus[].children | Array | 子菜单列表 |
数据模型
菜单对象 (Menu)
完整的菜单数据结构:
json
{
"id": "string", // 菜单ID
"parentId": "string", // 父菜单ID
"code": "string", // 菜单编码
"name": "string", // 菜单名称
"alias": "string", // 菜单别名
"path": "string", // 路由路径
"source": "string", // 图标标识
"component": "string", // 组件路径
"sort": 1, // 排序号
"category": 1, // 菜单分类
"action": 0, // 操作类型
"isOpen": 1, // 是否展开
"remark": "string", // 备注
"isDeleted": 0, // 是否删除
"children": [] // 子菜单列表
}字段说明
| 字段 | 类型 | 必填 | 说明 | 约束 |
|---|---|---|---|---|
| id | String | 是 | 菜单唯一标识 | 系统生成,不可修改 |
| parentId | String | 是 | 父菜单ID | 顶层菜单为"0" |
| code | String | 是 | 菜单编码 | 英文小写,全局唯一 |
| name | String | 是 | 菜单名称 | 2-50个字符 |
| alias | String | 否 | 菜单别名 | 用于前端显示 |
| path | String | 否 | 路由路径 | 前端路由路径 |
| source | String | 否 | 图标标识 | 图标资源标识 |
| component | String | 否 | 组件路径 | 前端组件路径 |
| sort | Integer | 是 | 排序号 | 数字越小越靠前 |
| category | Integer | 是 | 菜单分类 | 数值型分类标识 |
| action | Integer | 否 | 操作类型 | 0-普通操作 |
| isOpen | Integer | 否 | 是否展开 | 0-不展开,1-展开 |
| remark | String | 否 | 备注 | 菜单说明信息 |
| isDeleted | Integer | 是 | 是否删除 | 0-未删除,1-已删除 |
| children | Array | 否 | 子菜单列表 | 树形结构 |
枚举值说明
菜单分类 (category):
1: 菜单2: 按钮
操作类型 (action):
0: 普通操作1: 增加操作2: 修改操作3: 删除操作
是否展开 (isOpen):
0: 不展开1: 展开
是否删除 (isDeleted):
0: 未删除1: 已删除
权限体系说明
- 用户 ← 角色:多对多关系,一个用户可以有多个角色,一个角色可以分配给多个用户
- 角色 ← 菜单:多对多关系,一个角色可以有多个菜单,一个菜单可以分配给多个角色
- 用户 ← 角色 ← 菜单:用户通过角色间接获得菜单权限
错误码
业务错误码
| 错误码 | 说明 | 处理建议 |
|---|---|---|
| 2207 | 用户不存在 | 检查userId是否正确 |
| 2208 | 角色不存在 | 检查roleId是否正确 |
| 2209 | 菜单不存在 | 检查menuId是否正确 |
| 2210 | 角色菜单关联失败 | 检查角色和菜单ID是否正确 |
| 2211 | 用户角色关联失败 | 检查用户和角色ID是否正确 |
| 2212 | 操作类型错误 | 检查operation参数(add/remove/replace) |
| 2213 | 用户已有该角色 | 无需重复添加 |
| 2214 | 角色已分配该菜单 | 无需重复分配 |
系统错误码
| 错误码 | 说明 | 处理建议 |
|---|---|---|
| 1001 | 时间戳过期 | 同步系统时间 |
| 1002 | 重复请求 | 检查nonce生成逻辑 |
| 1003 | 签名验证失败 | 检查密钥配置 |
| 1004 | 解密失败 | 检查密钥配置 |
| 1005 | appId不存在 | 检查appId注册 |
| 1006 | 业务逻辑错误 | 根据具体错误处理 |
相关文档
文档版本: v3.0.0 最后更新: 2026-01-05