Permission 权限目录与接入说明
当前接入范围
Permission 接入分为三段:第三方程序维护自身 Permission、管理员给角色赋予 Permission、第三方从 OAuth 用户角色中计算当前用户的 Permission 集合。
当前共使用 5 个接口:3 个 Permission 目录接口、1 个角色更新接口、1 个 OAuth 用户信息接口。
参考文档:Cyber Hub ApiPost 文档。
接口名称、方法、路径和请求响应结构参考 ApiPost;参数校验、覆盖规则和副作用以当前服务端代码为准。
一、接入模型
1.1 三段流程
| 阶段 | 调用方 | 接口 | 用途 |
|---|---|---|---|
| 维护 Permission | 第三方程序 | POST /account/api/v1/permission | 添加自身定义的 Permission |
| 维护 Permission | 第三方程序 | DELETE /account/api/v1/permission | 删除自身不再使用的 Permission |
| 维护 Permission | 第三方程序 | GET /account/api/v1/permission/all | 查询自身已经登记的 Permission |
| 给角色赋权 | 管理员 | PUT /account/api/v1/role/info | 全量更新角色拥有的 Permission |
| 获取用户权限 | 第三方程序 | GET /account/api/v1/oauth/user | 获取当前用户角色并计算 Permission 并集 |
1.2 应用标识
同一个第三方应用必须统一使用一个稳定的应用标识,例如 vehicle-management:
| 使用位置 | 示例 |
|---|---|
Permission 的 source | vehicle-management |
查询参数 applicationType | vehicle-management |
| Permission ID 前缀 | vehicle-management:view |
| Role ID 前缀 | vehicle-management:admin |
source、applicationType 和角色前缀如果各写各的,后续查询和权限计算必然对不上。别在命名上整花活。
1.3 身份认证
所有请求通过 Header 携带访问令牌:
Authorization: Bearer <access-token>| 接口 | 路由权限 |
|---|---|
| 添加、删除、查询 Permission | 已登录用户(UserRoles) |
| 更新角色 | 管理员(AdminRoles) |
| 获取 OAuth 用户信息 | 已登录用户(UserRoles) |
UserRoles 和 AdminRoles 是接口访问角色,不是 Permission ID。
1.4 Permission 数据结构
| 字段 | 类型 | 添加时必填 | 说明 |
|---|---|---|---|
id | string | 是 | Permission 全局唯一 ID,推荐使用 <application>:<action> |
permissionName | string | 否 | 权限展示名称,接入方建议填写 |
description | string | 否 | 权限说明 |
source | string | 是 | Permission 所属应用,与 applicationType 对应 |
二、第三方程序维护自身权限信息
2.1 添加权限
批量登记第三方应用定义的 Permission。
请求
POST /account/api/v1/permission
Authorization: Bearer <access-token>
Content-Type: application/json[
{
"id": "vehicle-management:view",
"permissionName": "查看车辆",
"description": "允许查看车辆列表和详情",
"source": "vehicle-management"
},
{
"id": "vehicle-management:edit",
"permissionName": "编辑车辆",
"description": "允许新增和编辑车辆",
"source": "vehicle-management"
}
]请求体必须是数组。即使只添加一个 Permission,也不能直接提交单个对象。
成功响应
{
"message": "操作成功"
}当前行为
- 每一项的
id和source不能为空。 id是全局唯一键,不按source分区。- 已存在的
id会触发唯一键冲突,但控制器会忽略该冲突并继续返回成功。 - 重复提交不会更新已有 Permission 的名称、描述或来源,该接口不是 upsert。
- 服务端逐条写入且没有事务,批次中途失败时,前面已经写入的数据不会自动回滚。
2.2 删除权限
按 Permission ID 删除一个目录项。
请求
DELETE /account/api/v1/permission?permissionId=vehicle-management:edit
Authorization: Bearer <access-token>Query 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
permissionId | string | 是 | 要删除的 Permission ID |
成功响应
{
"message": "操作成功"
}当前行为
permissionId为空时返回参数错误。- 删除不存在的 ID 仍返回成功。
- 当前没有批量删除 Permission 的接口。
- 删除只处理 Permission 目录项,不会同步清理角色中保存的 Permission ID。
删除 Permission 前,管理员必须先通过 PUT /account/api/v1/role/info 更新所有引用该 ID 的角色。否则目录项虽然删除了,角色里仍会残留一条脏引用。
2.3 获取指定应用的权限
按应用标识查询第三方程序已经登记的 Permission。
请求
GET /account/api/v1/permission/all?applicationType=vehicle-management
Authorization: Bearer <access-token>Query 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
applicationType | string | 是 | 应用标识,必须与添加 Permission 时的 source 一致 |
成功响应
{
"permissions": [
{
"id": "vehicle-management:view",
"permissionName": "查看车辆",
"description": "允许查看车辆列表和详情",
"source": "vehicle-management"
},
{
"id": "vehicle-management:edit",
"permissionName": "编辑车辆",
"description": "允许新增和编辑车辆",
"source": "vehicle-management"
}
]
}当前行为
applicationType=cyberhub会转换成source=system。- 其他值按
source = applicationType精确查询。 - 当前代码没有显式拦截空值,但空值只会查询
source为空的记录,不会返回全部 Permission,因此调用方必须传值。 - 返回结果没有显式排序,调用方不得依赖数据库当前顺序。
三、管理员给角色赋予权限
管理员通过更新角色接口设置角色拥有的 Permission。
3.1 请求
PUT /account/api/v1/role/info
Authorization: Bearer <admin-token>
Content-Type: application/json{
"roleId": "vehicle-management:admin",
"permissionIds": ["vehicle-management:edit", "vehicle-management:view"]
}当前场景只提交 roleId 和 permissionIds,避免顺手修改角色名称、菜单或自定义数据。
3.2 请求字段
| 字段 | 类型 | 当前场景必填 | 说明 |
|---|---|---|---|
roleId | string | 是 | 要更新的角色 ID |
permissionIds | string[] | 是 | 角色更新后的完整 Permission ID 集合 |
permissionIds 采用全量覆盖语义:
- 省略字段:保持角色现有 Permission 不变。
- 传入空数组
[]:清空角色全部 Permission。 - 传入非空数组:使用新数组全量替换角色原有 Permission。
3.3 成功响应
接口返回更新后的角色信息,其中 permissions 是角色当前拥有的 Permission:
{
"roleId": "vehicle-management:admin",
"roleName": "车辆管理员",
"applicationType": "vehicle-management",
"code": "admin",
"custom": "",
"source": "user",
"sort": 0,
"menuList": [],
"permissions": [
{
"id": "vehicle-management:edit",
"permissionName": "编辑车辆",
"description": "允许新增和编辑车辆"
},
{
"id": "vehicle-management:view",
"permissionName": "查看车辆",
"description": "允许查看车辆列表和详情"
}
]
}3.4 当前行为
- 调用方必须具备管理员角色。
roleId必须对应已存在的角色。- 每个
permissionIds都必须对应已存在的 Permission。 - 后端会对 Permission ID 去重并按 ID 排序后保存。
- Permission 集合发生变化时,服务端会更新所有使用该角色用户的修改时间。
四、获取当前用户的权限集合
第三方程序不调用独立 Permission 查询接口,而是从 OAuth 用户信息的角色集合中计算自身应用的 Permission 并集。
4.1 获取用户信息
GET /account/api/v1/oauth/user
Authorization: Bearer <access-token>响应中的 roles 是角色对象数组。下面只展示权限计算需要的字段:
{
"id": "user-001",
"userId": "user-001",
"username": "demo",
"roles": [
{
"id": "cyberhub:admin",
"applicationType": "cyberhub",
"permission": "dashboard:view,service:all"
},
{
"id": "vehicle-management:viewer",
"applicationType": "vehicle-management",
"permission": "vehicle-management:view"
}
]
}4.2 按应用前缀筛选角色
第三方程序根据自身应用标识生成角色前缀。例如应用标识为 cyberhub 时,前缀为 cyberhub::
role.id.startsWith("cyberhub:")前缀必须包含末尾冒号,避免 app 错误匹配 app2:*。
4.3 合并角色 Permission
处理步骤:
- 将缺失的
roles按空数组处理。 - 只保留
role.id以目标应用前缀开头的角色。 - 将每个角色的
permission按逗号拆分。 - 去除每个 Permission ID 的首尾空白。
- 过滤空字符串。
- 使用集合去重,得到当前用户在该应用下的 Permission 并集。
TypeScript 示例:
type OAuthRole = {
id?: string;
permission?: string;
};
function collectApplicationPermissions(
roles: OAuthRole[] | null | undefined,
application: string
): string[] {
const prefix = application + ":";
const permissions = (roles ?? [])
.filter((role) => (role.id ?? "").startsWith(prefix))
.flatMap((role) => (role.permission ?? "").split(","))
.map((permission) => permission.trim())
.filter(Boolean);
return [...new Set(permissions)];
}返回值按集合语义使用,不要依赖数组顺序。
五、完整接入流程
- 第三方程序确定稳定的应用标识,并用它统一 Permission
source、applicationType和角色 ID 前缀。 - 调用
GET /permission/all?applicationType=<application>查询已经登记的 Permission。 - 调用
POST /permission添加缺少的 Permission。 - 管理员调用
PUT /role/info,把完整permissionIds集合赋给目标角色。 - 第三方程序调用
GET /oauth/user获取当前用户和角色集合。 - 按应用角色前缀筛选角色,拆分并合并
permission,得到当前用户的 Permission 集合。 - 下线 Permission 时,先由管理员从所有角色的
permissionIds中移除该 ID,再调用DELETE /permission。
接入自检:
- [ ]
source、applicationType和应用角色前缀使用同一个应用标识。 - [ ] Permission ID 全局唯一且命名稳定。
- [ ] 添加 Permission 时提交的是数组。
- [ ] 更新角色时提交的是完整
permissionIds集合。 - [ ] 权限计算按应用前缀筛选角色,并对 Permission ID 去空白、过滤空值和去重。
- [ ] 删除 Permission 前已清理全部角色引用。