Skip to content

Permission API ​

Permission API 是一个基于角色的访问控制(RBAC)服务,允许第三方应用管理用户角色和权限。你可以定义多个角色(Role),每个角色包含允许(Allow)和拒绝(Deny)两组权限标识,然后将角色分配给用户。多个角色之间通过优先级(Priority)进行合并,高优先级角色的决定覆盖低优先级角色。

概览 ​

项目说明
基础路径/permission/api/
认证方式Basic(应用模式)或 Bearer(用户模式)
数据格式JSON
角色数量上限每个应用最多 50 个
权限数量上限每个角色 allow + deny 合计最多 200 条

认证 ​

Permission API 支持两种认证模式,通过 Authorization 请求头区分:

应用模式(Basic) ​

使用应用的 client_id 和 client_secret 进行认证。应用模式可以执行所有角色和用户管理操作。

Authorization: Basic base64(client_id:client_secret)

⚠️ 安全提示:client_secret 拥有应用的完整管理权限。绝对不要将其写入分发给用户的客户端程序,否则密钥可被逆向提取。应用模式仅应在受信任的服务器环境或内部开发工具中使用。

推荐架构:面向用户的客户端应使用 Bearer 模式(用户 OIDC 登录),配合云函数和权限组实现业务逻辑。

用户模式(Bearer) ​

使用用户的 OAuth access_token 进行认证。用户模式下,可执行的操作取决于角色的可见性(Visibility)设置——详见下文「可见性与公开操作」章节。

Authorization: Bearer <access_token>

🔒 访问说明:用户模式的访问范围取决于角色的公开设置。角色默认为私有,用户无法通过 API 直接访问。如需客户端直接调用,请在开发者面板中开启对应的公开访问开关。推荐统一使用云函数处理权限逻辑。

应用模式(Basic 认证)不受可见性限制,始终可以执行所有操作。

重放防护 ​

所有 API 请求必须携带以下请求头以防止重放攻击:

请求头说明
X-Timestamp当前 Unix 时间戳(秒),与服务器时差不超过 ±5 分钟
X-Nonce随机唯一字符串,16~64 个字母数字字符,每次请求不同

核心概念 ​

角色(Role) ​

角色是权限的集合。每个角色有以下属性:

属性类型说明
namestring角色名称,在应用内唯一
descriptionstring角色描述
allowstring[]允许的权限标识列表
denystring[]拒绝的权限标识列表
prioritynumber优先级,数值越大优先级越高,用于多角色合并时的冲突解决
visibilitynumber可见性位掩码(详见下文)
publicMemberOpstring公开成员操作范围:add / remove / all
publicPermOpstring公开权限操作范围:add / remove / all

权限标识(Permission) ​

权限标识是自定义字符串,格式由你的应用自行约定(建议使用 resource.action 的形式,如 user.read、post.write)。

Allow / Deny 模型 ​

每个角色可以同时定义 allow(允许)和 deny(拒绝)权限。当用户拥有多个角色时,系统使用基于优先级的合并算法来计算最终权限:

  1. 将用户的所有角色按 priority 从高到低排序
  2. 对于每一个权限标识,第一个声明它的角色(无论是在 allow 还是 deny 中)拥有最终决定权
  3. 低优先级角色对同一权限的声明会被忽略

示例:

Role A (priority: 10)
  allow: ["read", "write"]
  deny:  ["delete"]

Role B (priority: 5)
  allow: ["delete", "admin"]
  deny:  ["write"]

合并结果:

  • read → 允许(Role A allow,优先级 10)
  • write → 允许(Role A allow,优先级 10;Role B deny 被忽略)
  • delete → 拒绝(Role A deny,优先级 10;Role B allow 被忽略)
  • admin → 允许(仅 Role B 声明,优先级 5)

检查权限时: 先检查合并后的 deny 列表(命中则拒绝),再检查 allow 列表(命中则允许),都未命中则拒绝。

可见性与公开操作 ​

角色默认是私有的——只有应用模式(Basic)可以操作。通过设置 visibility 位掩码,可以逐级开放给用户模式(Bearer):

公开权限查询开关 ​

除了角色级别的可见性控制外,还有一个应用级别的总开关控制权限查询类 API 的访问:

开关说明
公开权限查询控制用户模式(Bearer)是否可以调用「获取合并权限」和「检查权限」接口
  • 默认关闭:用户模式无法调用权限查询接口,仅可通过云函数 $permission.checkPermission() / $permission.getUserPermissions() 访问
  • 开启后:用户模式可以直接调用 GET /users/{uid}/permissions 和 GET /users/{uid}/check

💡 推荐做法:统一使用云函数处理权限验证逻辑,仅在确实需要客户端直接查询时开启此开关。

角色可见性位掩码 ​

位值含义
VIS_PUBLIC1公开角色:用户模式可以查看(列出、查询详情)
VIS_EDIT_MEMBER2公开编辑成员:用户模式可以分配/移除用户(受 publicMemberOp 限制)
VIS_EDIT_PERM4公开编辑权限:用户模式可以修改角色的 allow/deny(受 publicPermOp 限制)

visibility 是位掩码的组合值:

值含义
0完全私有(默认)
1公开只读
3公开 + 可编辑成员
7公开 + 可编辑成员 + 可编辑权限

publicMemberOp 和 publicPermOp 用于进一步细化公开操作的范围:

值含义
add仅允许添加操作
remove仅允许移除操作
all允许添加和移除操作

角色管理 ​

角色通过开发者管理面板创建和管理。如需在运行时动态控制角色的分配和权限,推荐使用 Cloud Function 中的 $permission 桥接对象。

API 接口 ​

列出所有角色 ​

http
GET /permission/api/roles

用户模式下仅返回 visibility 包含 VIS_PUBLIC 的角色。

响应:

json
{
  "status": "ok",
  "roles": [
    {
      "name": "admin",
      "description": "管理员",
      "allow": ["user.read", "user.write", "post.manage"],
      "deny": [],
      "priority": 100,
      "visibility": 0,
      "publicMemberOp": "all",
      "publicPermOp": "all"
    },
    {
      "name": "member",
      "description": "普通成员",
      "allow": ["user.read", "post.read"],
      "deny": ["post.delete"],
      "priority": 0,
      "visibility": 3,
      "publicMemberOp": "add",
      "publicPermOp": "all"
    }
  ]
}

获取角色详情 ​

http
GET /permission/api/roles/{roleName}

用户模式下角色必须公开(visibility & 1)。

路径参数:

参数类型说明
roleNamestring角色名称

响应:

json
{
  "status": "ok",
  "role": {
    "name": "admin",
    "description": "管理员",
    "allow": ["user.read", "user.write", "post.manage"],
    "deny": [],
    "priority": 100,
    "visibility": 0,
    "publicMemberOp": "all",
    "publicPermOp": "all"
  }
}

列出角色成员 ​

http
GET /permission/api/roles/{roleName}/members?page=1&limit=100

用户模式下角色必须公开(visibility & 1)。应用模式会返回邮箱、激活状态和分配者信息;用户模式只返回 uid、rid 和分配时间,避免泄露管理字段。

路径参数:

参数类型说明
roleNamestring角色名称

查询参数:

参数类型说明
pagenumber页码,默认 1
limitnumber每页数量,默认 100,最大 200

响应:

json
{
  "status": "ok",
  "roleName": "member",
  "total": 2,
  "page": 1,
  "limit": 100,
  "members": [
    {
      "uid": "94f48446-57ab-11f1-aa60-00163e15156d",
      "rid": "SmallMoonSet",
      "email": "user@example.com",
      "authState": 1,
      "assignedByUid": null,
      "assignedByRid": null,
      "assignedAt": "1780219728000"
    }
  ]
}

获取用户的角色列表 ​

http
GET /permission/api/users/{uid}/roles

用户模式下仅返回公开角色。

路径参数:

参数类型说明
uidstring用户 uid

响应:

json
{
  "status": "ok",
  "roles": [
    {
      "name": "member",
      "description": "普通成员",
      "allow": ["user.read", "post.read"],
      "deny": ["post.delete"],
      "priority": 0,
      "visibility": 3,
      "assignedBy": "app",
      "assignedAt": "2025-01-15T08:30:00.000Z"
    }
  ]
}

用户模式下额外返回 visibility、assignedBy(分配来源)、assignedAt(分配时间)字段。

获取用户的合并权限 ​

返回用户所有角色经过优先级合并后的最终 allow 和 deny 列表。

🔒 访问控制:用户模式(Bearer)调用此接口需要开启「公开权限查询」开关。未开启时仅可通过云函数 $permission.getUserPermissions(uid) 访问。

http
GET /permission/api/users/{uid}/permissions

路径参数:

参数类型说明
uidstring用户 uid

响应:

json
{
  "status": "ok",
  "allow": ["user.read", "user.write", "post.manage", "post.read"],
  "deny": ["post.delete"]
}

检查用户是否拥有指定权限 ​

检查逻辑:合并后 deny 命中 → false,allow 命中 → true,都未命中 → false。

🔒 访问控制:用户模式(Bearer)调用此接口需要开启「公开权限查询」开关。未开启时仅可通过云函数 $permission.checkPermission(uid, permission) 访问。

http
GET /permission/api/users/{uid}/check?permission={permission}

路径参数:

参数类型说明
uidstring用户 uid

查询参数:

参数类型说明
permissionstring要检查的权限标识

响应:

json
{
  "status": "ok",
  "hasPermission": true
}

给用户分配角色 ​

用户模式下,角色必须设置 visibility & VIS_EDIT_MEMBER,且 publicMemberOp 为 add 或 all。

http
POST /permission/api/users/{uid}/roles
Content-Type: application/json

路径参数:

参数类型说明
uidstring用户 uid

请求体:

json
{
  "roleName": "member"
}

响应:

json
{
  "status": "ok"
}

移除用户角色 ​

用户模式下,角色必须设置 visibility & VIS_EDIT_MEMBER,且 publicMemberOp 为 remove 或 all。

http
DELETE /permission/api/users/{uid}/roles/{roleName}

路径参数:

参数类型说明
uidstring用户 uid
roleNamestring角色名称

响应:

json
{
  "status": "ok"
}

更新角色权限 ​

用户模式下,角色必须设置 visibility & VIS_EDIT_PERM,且 publicPermOp 控制可执行的操作(添加/移除权限条目)。

http
PUT /permission/api/roles/{roleName}/permissions
Content-Type: application/json

路径参数:

参数类型说明
roleNamestring角色名称

请求体:

json
{
  "allow": ["user.read", "post.read", "post.write"],
  "deny": ["post.delete"]
}

响应:

json
{
  "status": "ok"
}

错误响应 ​

所有错误响应遵循统一格式:

json
{
  "error": "error_code",
  "error_description": "Human-readable error message"
}

常见错误码:

错误码HTTP 状态码说明
unauthorized401缺少 Authorization 请求头
invalid_client401无效的 Basic 凭据
invalid_token401无效的 Bearer token
forbidden403用户模式下角色不可见或操作不允许
service_not_enabled403应用未开通权限组服务
not_found404角色不存在或用户未分配此角色
duplicate400用户已拥有此角色
limit_exceeded400allow + deny 合计超过 200 条上限

使用示例 ​

典型游戏权限设计 ​

角色:admin (priority: 100, visibility: 0)
  allow: player.ban, player.kick, inventory.manage, chat.moderate
  deny:  (无)

角色:moderator (priority: 50, visibility: 1)
  allow: player.kick, chat.moderate
  deny:  player.ban

角色:muted (priority: 80, visibility: 3, publicMemberOp: add)
  allow: (无)
  deny:  chat.send, chat.color

角色:vip (priority: 10, visibility: 1)
  allow: chat.color, inventory.extra_slots
  deny:  (无)

如果一个用户同时拥有 muted(priority 80)和 vip(priority 10)角色:

  • chat.color → 拒绝(muted deny 优先级 80 > vip allow 优先级 10)
  • inventory.extra_slots → 允许(仅 vip 声明)
  • chat.send → 拒绝(muted deny)

在服务端检查权限 ​

javascript
// 检查玩家是否有封禁权限
const res = await fetch(
  `${API_BASE}/permission/api/users/${playerUid}/check?permission=player.ban`,
  { headers: { Authorization: `Basic ${btoa(`${clientId}:${clientSecret}`)}` } }
)
const { hasPermission } = await res.json()
if (!hasPermission) {
  throw new Error('You do not have permission to ban players')
}

在云函数中使用 $permission ​

javascript
// 云函数内通过 $permission 桥接对象操作权限
const roles = await $permission.getUserRoles(uid)
const perms = await $permission.getUserPermissions(uid)
const canBan = await $permission.checkPermission(uid, 'player.ban')

// 更新角色权限(需要应用有权操作该角色)
await $permission.updateRolePermissions('moderator', {
  allow: ['player.kick', 'chat.moderate', 'chat.pin'],
  deny: ['player.ban']
})

© 2026 StarEcho