Skip to content

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 的 sourcevehicle-management
查询参数 applicationTypevehicle-management
Permission ID 前缀vehicle-management:view
Role ID 前缀vehicle-management:admin

sourceapplicationType 和角色前缀如果各写各的,后续查询和权限计算必然对不上。别在命名上整花活。

1.3 身份认证

所有请求通过 Header 携带访问令牌:

http
Authorization: Bearer <access-token>
接口路由权限
添加、删除、查询 Permission已登录用户(UserRoles
更新角色管理员(AdminRoles
获取 OAuth 用户信息已登录用户(UserRoles

UserRolesAdminRoles 是接口访问角色,不是 Permission ID。

1.4 Permission 数据结构

字段类型添加时必填说明
idstringPermission 全局唯一 ID,推荐使用 <application>:<action>
permissionNamestring权限展示名称,接入方建议填写
descriptionstring权限说明
sourcestringPermission 所属应用,与 applicationType 对应

二、第三方程序维护自身权限信息

2.1 添加权限

批量登记第三方应用定义的 Permission。

请求

http
POST /account/api/v1/permission
Authorization: Bearer <access-token>
Content-Type: application/json
json
[
  {
    "id": "vehicle-management:view",
    "permissionName": "查看车辆",
    "description": "允许查看车辆列表和详情",
    "source": "vehicle-management"
  },
  {
    "id": "vehicle-management:edit",
    "permissionName": "编辑车辆",
    "description": "允许新增和编辑车辆",
    "source": "vehicle-management"
  }
]

请求体必须是数组。即使只添加一个 Permission,也不能直接提交单个对象。

成功响应

json
{
  "message": "操作成功"
}

当前行为

  • 每一项的 idsource 不能为空。
  • id 是全局唯一键,不按 source 分区。
  • 已存在的 id 会触发唯一键冲突,但控制器会忽略该冲突并继续返回成功。
  • 重复提交不会更新已有 Permission 的名称、描述或来源,该接口不是 upsert。
  • 服务端逐条写入且没有事务,批次中途失败时,前面已经写入的数据不会自动回滚。

2.2 删除权限

按 Permission ID 删除一个目录项。

请求

http
DELETE /account/api/v1/permission?permissionId=vehicle-management:edit
Authorization: Bearer <access-token>

Query 参数

参数类型必填说明
permissionIdstring要删除的 Permission ID

成功响应

json
{
  "message": "操作成功"
}

当前行为

  • permissionId 为空时返回参数错误。
  • 删除不存在的 ID 仍返回成功。
  • 当前没有批量删除 Permission 的接口。
  • 删除只处理 Permission 目录项,不会同步清理角色中保存的 Permission ID。

删除 Permission 前,管理员必须先通过 PUT /account/api/v1/role/info 更新所有引用该 ID 的角色。否则目录项虽然删除了,角色里仍会残留一条脏引用。

2.3 获取指定应用的权限

按应用标识查询第三方程序已经登记的 Permission。

请求

http
GET /account/api/v1/permission/all?applicationType=vehicle-management
Authorization: Bearer <access-token>

Query 参数

参数类型必填说明
applicationTypestring应用标识,必须与添加 Permission 时的 source 一致

成功响应

json
{
  "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 请求

http
PUT /account/api/v1/role/info
Authorization: Bearer <admin-token>
Content-Type: application/json
json
{
  "roleId": "vehicle-management:admin",
  "permissionIds": ["vehicle-management:edit", "vehicle-management:view"]
}

当前场景只提交 roleIdpermissionIds,避免顺手修改角色名称、菜单或自定义数据。

3.2 请求字段

字段类型当前场景必填说明
roleIdstring要更新的角色 ID
permissionIdsstring[]角色更新后的完整 Permission ID 集合

permissionIds 采用全量覆盖语义:

  • 省略字段:保持角色现有 Permission 不变。
  • 传入空数组 []:清空角色全部 Permission。
  • 传入非空数组:使用新数组全量替换角色原有 Permission。

3.3 成功响应

接口返回更新后的角色信息,其中 permissions 是角色当前拥有的 Permission:

json
{
  "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 获取用户信息

http
GET /account/api/v1/oauth/user
Authorization: Bearer <access-token>

响应中的 roles 是角色对象数组。下面只展示权限计算需要的字段:

json
{
  "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:

text
role.id.startsWith("cyberhub:")

前缀必须包含末尾冒号,避免 app 错误匹配 app2:*

4.3 合并角色 Permission

处理步骤:

  1. 将缺失的 roles 按空数组处理。
  2. 只保留 role.id 以目标应用前缀开头的角色。
  3. 将每个角色的 permission 按逗号拆分。
  4. 去除每个 Permission ID 的首尾空白。
  5. 过滤空字符串。
  6. 使用集合去重,得到当前用户在该应用下的 Permission 并集。

TypeScript 示例:

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)];
}

返回值按集合语义使用,不要依赖数组顺序。

五、完整接入流程

  1. 第三方程序确定稳定的应用标识,并用它统一 Permission sourceapplicationType 和角色 ID 前缀。
  2. 调用 GET /permission/all?applicationType=<application> 查询已经登记的 Permission。
  3. 调用 POST /permission 添加缺少的 Permission。
  4. 管理员调用 PUT /role/info,把完整 permissionIds 集合赋给目标角色。
  5. 第三方程序调用 GET /oauth/user 获取当前用户和角色集合。
  6. 按应用角色前缀筛选角色,拆分并合并 permission,得到当前用户的 Permission 集合。
  7. 下线 Permission 时,先由管理员从所有角色的 permissionIds 中移除该 ID,再调用 DELETE /permission

接入自检:

  • [ ] sourceapplicationType 和应用角色前缀使用同一个应用标识。
  • [ ] Permission ID 全局唯一且命名稳定。
  • [ ] 添加 Permission 时提交的是数组。
  • [ ] 更新角色时提交的是完整 permissionIds 集合。
  • [ ] 权限计算按应用前缀筛选角色,并对 Permission ID 去空白、过滤空值和去重。
  • [ ] 删除 Permission 前已清理全部角色引用。