全平台客户端
AuthKeystone 的 OAuth client 体系:三级可见性(visibility)、门户展示开关(portal_visible)、 自助接入、越级提升申请工作流,以及管理端操作。
1. 三级 visibility(可见性)
每个 OAuth client 有一个 visibility 字段,决定谁能看到、谁能写。三级从低到高:
| 级别 | 数值 | 谁能看到(list) | 谁能写(can_write_client) | 典型场景 |
|---|---|---|---|---|
user | 0 | 仅 owner(owner_user_id) | 仅 owner | 普通用户自助创建的私有 client |
org | 1 | 同组织成员(org_id 匹配) | 该组织 org_admin(system:oauth:client:edit + org 匹配) | 团队/企业共享的 client |
system | 2 | 全平台所有人 | 平台 admin | 官方 / 全局 client |
可见性查询(list_visible_clients)的过滤条件:
visibility = 'system'
OR (visibility = 'org' AND org_id = ?)
OR (visibility = 'user' AND owner_user_id = ?)
应用门户(GET /api/user/apps)与 API Key 的应用选择器共用这一数据源,再由调用方按 portal_visible 决定是否展示。
写权限按级绑定(越级不可直接改)
visibility 同时绑定写权限:只能由当前级的 authority 改写。越级提升(user→org→system)不能直接改字段,必须走提升申请工作流(见第 4 节)——防止 owner 私自把 user 级 client 提到 system 级越权。
2. portal_visible(门户展示开关)
portal_visible 是独立于 visibility 的布尔字段,只控制是否在「我的应用」门户展示,不影响权限:
true→ 出现在GET /api/user/apps列表,普通用户可见可点false→ 不出现在门户(即使 visibility 允许看到,也不展示)
典型用法:内部工具、后台 client 关掉;面向终端用户的应用打开。管理端可在 OAuth client 列表内联切换。
3. 自助接入(普通用户自己建 client)
普通用户无需 admin 权限即可注册自己的 OAuth client(默认 visibility=user)。
支持两种类型:Web 应用(用户登录接入)与 M2M 服务身份(服务间调用)。
3.1 用户域端点(/api/my/clients,按 owner 过滤)
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/my/clients | 列出我(owner)的 client |
| POST | /api/my/clients | 创建我的 client(固定 visibility=user) |
| DELETE | /api/my/clients/:client_id | 删除我的 client(校验 owner 归属) |
创建响应里 client_secret 明文仅返回一次。匿名访客须先转正(POST /api/auth/upgrade)才能创建。
存量配额(2026-09 起):每用户名下 client 总数受上限约束(管理台「系统设置」的
self_service_client_quota,默认 10,热生效;0 = 关闭自助创建)。GET 列表响应带
{quota, used, remaining} 余量;超限创建返回 400(删除 client 即释放名额)。admin 通道
创建的 client 不绑 owner,不受此限。
通用约束(防越权):
visibility固定为user,不能自助指定 org/system- grant 白名单:
authorization_code/refresh_token/client_credentials redirect_uri必须http(s)://- 存量配额:见上,资源卫生约束(权限越权已由委托模型/白名单独立挡住)
3.2 两种客户端类型(grant_types 决定)
| Web 应用 | M2M 服务身份 | |
|---|---|---|
| grant_types | authorization_code(+ refresh_token,缺省即此组合) | 仅 client_credentials |
| 典型场景 | Web / SPA 应用接入登录 | 服务间调用、定时任务、机器人 |
| redirect_uris | 必填(授权码回调) | 免填(无浏览器回调) |
| scope | 只能从 openid / profile / email 选——不能塞系统 scope(如 auth:permissions、auth:org),防自助 client 越权拿权限/组织字段 | 自动置空(M2M 无用户上下文,scope 无意义) |
| 权限通道 | scope 经用户授权(consent) | service_permissions 委托(见 3.3) |
| is_public | 允许(前端 SPA,强制 PKCE) | 不允许——M2M 须机密客户端 |
| is_first_party | 默认 true(第一方免 consent) | 强制 false(无浏览器/consent 上下文) |
混合 grant(authorization_code + client_credentials)按 Web 型处理,不能携带 service_permissions——需要服务身份时单独创建一个纯 M2M client。
3.3 M2M 委托权限模型(service_permissions)
user 级 M2M 的 token 权限不是平台分配,而是创建者对自身权限的委托(与 GitHub OAuth Apps「人人可建、权限不超出本人」同款分层):
service_permissions必须是创建者自身权限(claims.permissions)的子集——只能委托自己有的,超出范围创建报 400- 换 token:
POST /oauth/token(grant_type=client_credentials)→ 机器 token 的sub/aud= client_id、token_type=client、permissions= 委托的权限集、TTL 15 分钟、带jti - 委托校验在创建时执行,配置存于 client;自助面暂无编辑端点,调整委托 = 删除重建
- 非 user 级(org/system,管理端创建)的 M2M 走命名空间白名单(
platform:/capability:/agent:),与 user 级委托是两条权限界
3.4 标准 DCR(RFC 7591/7592,机器自助接入)
下游服务也可走标准动态客户端注册,无需人工:
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /oauth/register | 注册 client,返回 registration_access_token |
| GET/PUT/DELETE | /oauth/register/:client_id | 用 registration_access_token 管自己注册的 client |
4. visibility 提升申请工作流
owner(或当前级写权者)想让 client 从 user 升到 org/system,不能直接改,要走申请→审批:
申请方(当前级写权者:owner / org_admin)
│ POST /api/oauth-clients/:client_id/promote { to_visibility: "org"|"system", note? }
▼
待审批(pending)
│ 目标级 authority 审批:
│ to=system → 平台 admin
│ to=org → 该组织 org_admin(system:oauth:client:edit + org 匹配)
▼
POST /api/promotion-requests/:id/decide { approve: bool, note? }
│
├─ approve → client.visibility 改为目标级(to=org 时归入申请指定组织)
│ ⚠ 写权随之转交目标级 authority,原 owner 失去直接编辑权
└─ reject → 状态记为 rejected,visibility 不变
端点
| 方法 | 路径 | 权限 | 说明 |
|---|---|---|---|
| POST | /api/oauth-clients/:client_id/promote | 当前级写权者 | 发起提升申请(to 须高于 from,且只能 org/system) |
| GET | /api/promotion-requests | - | 申请列表:平台 admin 看全部;org_admin 看 to=org 本组织;其余看自己提的 |
| POST | /api/promotion-requests/:id/decide | 目标级 authority | 审批(approve/reject) |
关键规则
to_visibility必须高于from_visibility(user < org < system),且只能是org或systemto=org时,目标组织 = 申请人所在组织- approve 后写权转交:原 owner 不再能直接编辑该 client——这是有意设计,避免提升后权限与管理权错配
5. 管理端(平台 admin / org_admin)
| 方法 | 路径 | 权限 | 说明 |
|---|---|---|---|
| GET | /api/admin/oauth/clients | system:oauth:client:list | client 列表 |
| POST | /api/admin/oauth/clients | system:oauth:client:create | 创建(可直接指定 visibility) |
| PUT | /api/admin/oauth/clients/:client_id | system:oauth:client:edit | 更新(含 visibility / portal_visible) |
| DELETE | /api/admin/oauth/clients/:client_id | system:oauth:client:delete | 删除 |
| POST | /api/admin/oauth/clients/:client_id/rotate | system:oauth:client:edit | 轮换 client_secret |
| GET/POST | /api/admin/oauth/clients/:client_id/scopes | system:oauth:client:* | 查看 / 配置 client 的 scope |
| GET/POST/PUT/DELETE | /api/admin/client-scopes | system:oauth:client:* | scope 全生命周期 + 用量追踪 |
平台 admin 可设任意 visibility;org_admin 仅能管本组织
visibility=org的 client(Phase 2 写权限按级绑定)。