权限
面向组织管理员。每项任务需要对应权限。只有平台管理员可以修改 /v1/platform
下的设置。从管理员手册开始。
本页说明 OpenBot 如何决定调用者是否可以做某件事。每次调用 /v1
都写明它需要什么:对某个资源的一个操作。OpenBot 在调用运行之前检查它。
OpenBot 用 ability 库来做这件事。这个模型有四个部分:
| 部分 | 含义 |
|---|---|
| Resource(资源) | 一类可以操作的东西,例如 Chat 或 Bot。每一类都有一组操作和一个路径。 |
| Rule(规则) | 当它的条件为真时,对某些资源上的某些操作说 Allow(允许)或 Deny(拒绝)。 |
| Policy(策略) | 一棵由规则组成的树。它对一个请求给出一个答案:允许、拒绝,或没有答案。 |
| Role(角色) | 一个有名字的策略,例如 Member 或 Administrator。组织可以添加自己的角色。 |
成员得到其角色的策略,再加上自己的成员策略。用户令牌还有它自己的策略,两者都必须允许这次调用。平台可以添加一个上限(ceiling),其中的拒绝规则对每个组织都生效。见 检查顺序。
用 GET /v1/organization/resources
列出它们。每一项都有一个资源的类型(kind)、操作、字段和路径。
| 资源 | 操作 | 允许什么 |
|---|---|---|
Chat |
read |
读取 Chats、它们的历史,以及它们交出去的工作。 |
Chat |
write |
修改、中断和删除 Chats,并取消它们交出去的工作。 |
Chat |
run |
给 Bots 发消息,让它们在一个 Chat 中工作。 |
File |
read |
读取你的文件和它们的字节。 |
File |
write |
上传和删除你的文件。 |
Request |
resolve |
回答你的 Bots 对新能力提出的 request。 |
Bot |
read |
读取 Bots,以及它们的记忆、Rules 和 Grants。 |
Bot |
write |
创建和修改 Bots,以及它们的记忆、Rules 和 Grants。 |
Bot |
delegate |
从客户端或另一个 Bot,把工作交给某个 Bot。 |
Bot |
share |
邀请别人使用某个 Bot,并管理它的成员。 |
Trigger |
read |
读取触发器:它们的计划时间和 webhook。 |
Trigger |
write |
创建、修改和删除触发器,并设置它们的 webhook 密钥。 |
Channel |
read |
读取组织的 Channels,以及与它们关联的人。 |
Channel |
write |
创建、修改和删除 Channels,设置它们的密钥,并解除人的关联。 |
Channel |
use |
与 Channel 的 Bot 交谈,并让你的 Bots 向它发消息。 |
ChannelIdentity |
read |
读取你在 Channel 平台上关联的账户。 |
ChannelIdentity |
write |
关联和解除关联你在 Channel 平台上的账户。 |
Computer |
read |
读取 Computers、可以使用它们的 Bots,以及它们的用量。 |
Computer |
write |
创建、修改和删除 Computers,配对机器,并创建连接器令牌。 |
Computer |
use |
运行命令、修改文件、打开端口和使用桌面,并让你的 Bots 使用它们。 |
ComputerProvider |
read |
读取 Computer 提供方的账户。 |
ComputerProvider |
write |
添加、修改和删除 Computer 提供方的账户,以及它们的密钥。 |
ComputerProvider |
use |
用 Computer 提供方的账户创建 Computers。 |
Vault |
read |
读取 Vaults、它们的条目,以及可以使用它们的 Bots。从不显示机密。 |
Vault |
write |
添加、修改和删除 Vaults 和它们的条目,并设置值。 |
Vault |
use |
让你的 Bots 在 Code Mode 中使用 Vaults。 |
SecretProvider |
read |
读取机密提供方的账户。 |
SecretProvider |
write |
添加、修改和删除机密提供方的账户,以及它们的令牌。 |
SecretProvider |
use |
让 Vault 条目从机密提供方的账户读取机密。 |
Connection |
read |
读取 App 连接和 App 账户。 |
Connection |
write |
创建、修改和删除 App 连接,并登录 App 账户。 |
App |
use |
查找 Apps,并使用 App 操作和 App 视图。 |
App |
publish |
为你发布的 Apps 使用开发者工具。 |
Model |
use |
为 Chat 选择模型,并在模型目录中看到它。 |
Token |
read |
列出 API 令牌。 |
Token |
write |
创建和撤销 API 令牌。 |
Organization |
read |
读取组织和它的设置。 |
Organization |
write |
修改组织和它的设置。 |
Member |
read |
列出成员、他们的角色和策略。 |
Member |
write |
修改成员的角色、策略和状态,以及移除成员。 |
Role |
write |
创建、修改和删除组织的自定义角色。 |
ModelProvider |
read |
读取组织的模型和模型提供方。密钥永远不会显示。 |
ModelProvider |
write |
添加、修改和移除组织的模型、模型提供方和密钥。 |
Sso |
read |
读取邮箱域名和 SSO 连接。 |
Sso |
write |
添加和验证邮箱域名,以及修改 SSO 连接。 |
AuditLog |
read |
读取审计日志。 |
Usage |
read |
读取模型用量和它的费用,以及组织的额度。 |
Budget |
read |
读取预算,以及已经花了多少。 |
Budget |
write |
创建、修改和删除预算。 |
Platform |
read |
读取平台设置、组织、管理员,以及共享的模型和模型提供方。 |
Platform |
write |
修改平台设置、组织、管理员,以及共享的模型和模型提供方。 |
Platform 只供平台管理员使用。见 平台。
API 参考 列出了所有路由。@openbot-build/api
中的契约说明了每个路由需要哪个操作。
路径把每个资源放在一棵树中。一条规则可以涵盖树的一部分。
| 资源 | 路径 |
|---|---|
Chat、File、Request、Connection |
org / <org> / user / <user> / <kind> / <id> |
Bot、Trigger、Computer、ComputerProvider、Vault、SecretProvider |
org / <org> / user / <owner> / <kind> / <id> |
App、Token、ChannelIdentity |
org / <org> / user / <user> / <kind> |
Channel |
org / <org> / channel / <id> |
Model |
org / <org> / model / <provider> / <id> |
Organization、Member、Role、ModelProvider、Sso、AuditLog、Usage、Budget |
org / <org> |
Platform |
platform |
类型部分是小写的类型名,单词之间用 _,例如 computer_provider。App 用
apps。
共享的 Bot、触发器、Computer 或 Computer 提供方没有所有者。它的 ownerUserId
字段是
null。由另一个 Bot 拥有的 Bot,使用其所有者树最顶层的所有者。当一个 Bot 创建另一个 Bot 时,它所服务的成员需要对那个所有者的 Bots 拥有
write。
策略是 JSON 文本。HTTP 请求和响应中的 policy 和 ceiling
字段都是字符串。要发送策略对象,先对该字段调用一次
JSON.stringify(policy),再把外层请求编码为 JSON。类型化客户端通过策略 Codec(读取和写入策略的 Schema)完成这一步。
下面的文本让调用者读取和修改自己的 Chats:
{ "_tag": "Rules", "algorithm": "denyOverrides", "rules": [ { "_tag": "Allow", "actions": ["read", "write"], "resources": ["Chat"], "when": { "_tag": "Under", "prefix": [ { "_tag": "Literal", "value": "org" }, { "_tag": "Principal", "path": "organizationId" }, { "_tag": "Literal", "value": "user" }, { "_tag": "Principal", "path": "userId" } ] } } ]}OpenBot 在读取每个策略时都会检查它。不存在的类型、操作或字段会返回
400。请求中的一个策略最多有 100 条规则,最多 8 层深。
Ability
3.1.0 不设库的大小、深度或搜索上限。上面的 OpenBot 请求限制仍然有效。字段列表只能使用实际路径或
*,不能使用 owner* 这样的模式。
从 Ability 2 升级到 3 时,停止所有服务器并运行
openbot-migrate。迁移把平台 ceiling 从对象转为 JSON 文本。角色、成员和令牌的策略列已经存储 JSON 文本。客户端必须为
policy 和 ceiling
发送字符串。旧策略必须使用有效的字段。无法加载的策略不会授予访问权限。
一条规则有这些字段:
| 字段 | 含义 |
|---|---|
_tag |
Allow 或 Deny。 |
actions |
操作。* 表示每个操作。 |
resources |
类型,例如 Chat。* 表示每个类型。 |
when |
可选。条件。没有它时,规则涵盖这些类型的每个值。 |
reason |
可选。一个原因。拒绝规则产生的 Forbidden 错误会显示它。 |
一组规则有一个
algorithm(算法)。当多条规则都适用时,它决定由哪条规则给出答案:
| 算法 | 胜出者 |
|---|---|
denyOverrides |
拒绝规则胜过每条允许规则。 |
permitOverrides |
允许规则胜过每条拒绝规则。 |
firstApplicable |
第一条适用的规则。 |
lastApplicable |
最后一条适用的规则。 |
策略也可以把多个策略组合在一起:
| 节点 | 答案 |
|---|---|
{"_tag":"All","policies"} |
每个策略都必须允许。一个拒绝就足以拒绝。 |
{"_tag":"Any","policies"} |
一个允许就足够。 |
{"_tag":"FirstOf","policies"} |
第一个给出允许或拒绝的策略。 |
{"_tag":"Ceiling","cap","policy"} |
来自 cap 的拒绝总是胜出。来自 cap 的允许不起作用。 |
条件检查资源的字段和路径:
| 节点 | 何时为真 |
|---|---|
{"_tag":"Compare","op","field","value"} |
字段与值比较成立。op 是 eq、ne、lt、lte、gt 或 gte。 |
{"_tag":"In","field","values"} |
字段等于其中一个值。 |
{"_tag":"Exists","field"} |
字段不是 null。 |
{"_tag":"Under","prefix"} |
资源的路径以这个前缀开头。 |
{"_tag":"And"/"Or","conditions"} |
逻辑。 |
{"_tag":"Not","condition"} |
逻辑。 |
{"_tag":"True"}、{"_tag":"False"} |
总是,或从不。 |
值是 {"_tag":"Literal","value":...},或调用者的一个字段:
{"_tag":"Principal","path":"userId"} 或
"organizationId"。调用者没有值的字段永远不会匹配,用 ne 时也一样。
下面是最常用的条件:
| 条件 | 涵盖 |
|---|---|
Under,前缀为 org 和调用者的 organizationId |
组织中的一切。 |
Under,前缀为 org、organizationId、user、userId |
调用者的一切。 |
对 ownerUserId 用 Compare eq,值为 null |
共享的 Bots、触发器或 Computers。 |
对 id 用 Compare eq |
某一个资源。 |
成员的每个策略只在该成员的组织中生效。指定其他组织的规则不会给出任何东西。
Model 上的 use 涵盖成员可以为 Chat 选择的模型。
GET /v1/organization/model_catalog
只显示这些模型。下面的规则禁止成员使用某一个模型提供方:
{ "_tag": "Deny", "actions": ["use"], "resources": ["Model"], "when": { "_tag": "Compare", "op": "eq", "field": "provider", "value": { "_tag": "Literal", "value": "prov_4c1e..." } }}OpenBot 检查三个策略:
- 平台的上限(ceiling)。它只有拒绝规则,并且对每个组织都生效。见 Platform。
- 成员策略:成员角色的策略,加上成员自己的成员策略。其中任何一个的拒绝规则都会胜出。
- 令牌策略,当调用者使用用户令牌时。
任何地方出现拒绝,答案都是否。成员策略,以及有令牌策略时的令牌策略,也都必须允许这次调用。没有答案时,答案就是否。
OpenBot 每次检查时都会重新读取这些策略。所以对角色、成员或令牌的修改会立即生效。
执行会分别保存资源所有者与发起人。对于 Channel 工作,发言人和每个已保存的调用者都必须通过针对真实资源所有者的策略检查。后续检查会重新读取他们当前的权限。审批不能改变这个所有者,也不能去掉令牌限制。
列表(例如
GET /v1/triggers)只包含调用者可以读取的资源。OpenBot把策略变成列表上的一个条件,对大多数列表来说就在数据库查询本身中完成。所以对某一个资源的拒绝规则,也会把它从列表中隐藏。
当资源没有成员所有者时,列表条件和单项检查的结果相同。例如,
NOT (ownerUserId = "member") 会包含 ownerUserId 为 null 的共享资源。
Chat、文件、App 连接和 Channel 列表都在数据库查询中应用策略。拒绝规则只会隐藏匹配的项。如果没有可读的项,列表就是空的。文件分页和下一页游标只计算调用者可读的文件。文件游标必须仍属于调用者,并通过当前的读取权限检查。
创建 Chat、文件、App 连接或 Channel 仍需要对这类资源的完整范围有 write
权限。列表过滤不会授予写入权限。
令牌永远不会超过它的成员
Section titled “令牌永远不会超过它的成员”用户令牌必须通过它自己的策略和它的成员的策略。所以令牌能做的可以比它的成员少,但永远不会更多。如果管理员拿走了成员的某个角色,这个成员的每个令牌也会失去它。
创建时没有 policy
的令牌会得到下面这个策略。它允许它的成员能做的一切,但不包括对令牌和平台的操作:
{ "_tag": "Rules", "algorithm": "denyOverrides", "rules": [ { "_tag": "Allow", "actions": ["*"], "resources": ["Chat", "File", "Request", "...", "Budget"] } ]}下面的例子创建一个只能读取你的 Chats 的令牌:
curl -b cookies.txt \ -H "Origin: https://api.example.com" \ -H "Content-Type: application/json" \ -d '{"name":"Dashboard","policy":"{\"_tag\":\"Rules\",\"algorithm\":\"denyOverrides\",\"rules\":[{\"_tag\":\"Allow\",\"actions\":[\"read\"],\"resources\":[\"Chat\"]}]}"}' \ https://api.example.com/v1/user/tokens这条规则没有条件,但成员的策略仍然把令牌限制在你可以读取的范围内。
用 GET /v1/organization/roles
列出角色。列表中有内置角色和组织的自定义角色。每个角色有 builtin: true 或
builtin: false,以及它的 policy。
每个组织都有这些角色。它们不能修改。修改会返回 409 和 RoleReadOnly。
| 角色 | 能做什么 |
|---|---|
super_administrator |
组织中的一切。只有 Super Administrator 能给出或拿走这个角色。 |
administrator |
管理组织、成员、共享的 Bots、共享的触发器、共享的 Computers 和 Channels,并读取审计日志。只能操作自己的 Chats 和连接。 |
administrator_read_only |
读取组织、成员、用量、预算和审计日志,并读取共享的 Bots、触发器、Computers 和 Channels。只能操作自己的 Chats 和连接。 |
member |
操作自己的 Bots、Chats、触发器、Computers、连接和令牌,使用组织共享的 Bots、触发器、Computers、Channels 和模型,并读取组织设置。 |
auditor |
读取组织、成员、用量、预算和审计日志。不能做其他事。 |
一些内置角色还可以操作角色、模型提供方、SSO、Channels、用量和预算:
| 角色 | 组织功能的额外资源 |
|---|---|
super_administrator |
每个资源上的每个操作,但 Platform 除外。 |
administrator |
Role、ModelProvider、Sso、Channel、Usage 和 Budget 上的每个操作。 |
administrator_read_only |
ModelProvider、Sso、Channel、Usage 和 Budget 上的 read。 |
auditor |
Usage 和 Budget 上的 read。 |
要让成员的权限比角色少,请给成员一个带拒绝规则的策略。下面的例子禁止成员运行工作,但允许他们读取自己的Chats:
curl -X PATCH -b cookies.txt \ -H "Origin: https://api.example.com" \ -H "Content-Type: application/json" \ -d '{"policy":"{\"_tag\":\"Rules\",\"algorithm\":\"denyOverrides\",\"rules\":[{\"_tag\":\"Deny\",\"actions\":[\"run\"],\"resources\":[\"Chat\"]}]}"}' \ https://api.example.com/v1/organization/members/u_456组织可以添加自己的角色。自定义角色有名称、描述和策略。它的 ID 以 role_
开头。创建、修改和删除自定义角色需要 Role 上的 write。
curl -H "Authorization: Bearer $OPENBOT_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"Reviewer","description":"Reads Chats and answers requests.","policy":"{\"_tag\":\"Rules\",\"algorithm\":\"denyOverrides\",\"rules\":[{\"_tag\":\"Allow\",\"actions\":[\"read\",\"resolve\"],\"resources\":[\"Chat\",\"Request\"],\"when\":{\"_tag\":\"Under\",\"prefix\":[{\"_tag\":\"Literal\",\"value\":\"org\"},{\"_tag\":\"Principal\",\"path\":\"organizationId\"},{\"_tag\":\"Literal\",\"value\":\"user\"},{\"_tag\":\"Principal\",\"path\":\"userId\"}]}}]}"}' \ https://api.example.com/v1/organization/roles| 路由 | 作用 |
|---|---|
POST /v1/organization/roles |
创建一个自定义角色。 |
GET /v1/organization/roles/:roleId |
读取一个角色。 |
PATCH /v1/organization/roles/:roleId |
修改一个自定义角色。 |
DELETE /v1/organization/roles/:roleId |
删除一个自定义角色。 |
- 角色的允许规则不能给出你自己做不到的事。OpenBot 把你当作调用者来测试每条允许规则。对于这条规则在组织中允许的每个值,你都必须能做它的操作。这个答案是精确的:它会看资源的字段和路径。一条不允许任何值的规则什么也不给,所以它可以通过。否则 OpenBot 返回
403和Forbidden。 - 修改会立即对拥有该角色的每个成员生效。
- 当某个成员或组织的
defaultRoles正在使用一个角色时,你不能删除它。OpenBot 返回409和RoleInUse。
用 PATCH /v1/organization/members/:userId 把自定义角色给成员。见
组织。
Platform 上的操作供平台管理员使用。它的路径是
platform,所以任何关于组织的规则都不会涵盖它。
- 组织中的任何角色都不会给出它们,即使是
super_administrator也不会。 - 上限对它们不生效,所以上限永远不会把平台管理员锁在外面。
- 平台管理员的用户令牌,只有在它自己的策略允许它们时,才会得到它们。
令牌示例见 Platform。
| 状态码 | 错误 | 何时出现 |
|---|---|---|
400 |
Schema 错误 | 策略指定了不存在的类型、操作或字段。 |
403 |
Forbidden |
没有规则允许这次调用,或者有规则拒绝了它。见下面的响应体。 |
404 |
RoleNotFound |
组织没有这个 ID 的角色。 |
409 |
RoleReadOnly |
你试图修改或删除内置角色。 |
409 |
RoleInUse |
某个成员或默认角色仍在使用这个角色。 |
503 |
PolicyUnavailable |
OpenBot 现在无法读取调用者的角色和策略。 |
Forbidden 的响应体会写出操作和类型。当答案来自一条拒绝规则时,它还有这条规则的
reason:
{ "_tag": "Forbidden", "action": "write", "kind": "Chat"}你只能访问自己的 Chats 和连接。另一个成员的 Chat 会返回
404,就像它不存在一样。你不能读取的 Bot、触发器或 Computer 也会同样返回
404。