资源访问控制(ACL)

OpenViking ACL 用于在同一个 account 内,把共享资源目录或文件授权给用户或用户组。ACL 不改变 account 隔离:任何授权都只在当前 account 内生效。

ACL 采用协作文档式的继承模型。目录授权默认持续作用于所有后代,子目录和文件可以继续增加直接授权,也可以用 restricted 模式在某个节点切断继承权限。

适用 URI

ACL 只作用于共享资源:

viking://resources/...
  • viking://resources/... 的 account ADMIN 隐式拥有 manage

  • viking://resources 是固定共享 scope,本身不能设置直接 ACL;ACL 从它下面的文件和目录开始。

  • viking://user/{user_id}/resources/... 是个人私有区,不接受 ACL。需要分享时,将资源移动到有权写入的共享目录,并继承该目录的 ACL。

隐式管理权不会写入 ACL 条目,也不能被 ACL 删除。它保证共享资源始终有人能够首次设置或恢复权限。

Principal 与权限级别

ACL 条目使用带类型的 principal:

  • user:{user_id}:当前 account 内的用户。

  • group:{group_id}:由调用者指定、在当前 account 内唯一的用户组 ID。

  • user:*:当前 account 内任意用户。

不支持 group:*。用户组是平铺结构;修改成员关系不会重写资源 ACL 或 context 记录,而是在下一次请求构造 RequestContext.group_ids 时生效。 请求创建的异步解析和语义任务会携带同一份 group 身份。add-resource 写入目标通过鉴权后,自动语义维护会保留原调用者身份,并显式使用内部 ACL bypass,不会把调用者角色改成 ADMIN

Level允许的操作
read读取、列目录、find/search/grep
writeread 的能力,以及写入、创建、删除或移动文件、修改 tags
managewrite 的能力,以及删除或移动目录、管理 ACL

高等级包含低等级能力。授予 manage,等价于同时授予 readwrite

继承规则

普通节点合并 direct 与 inherited;restricted 节点只使用 direct:

effective(node) = direct(node) + (acl_mode(node) == "restricted" ? empty : inherited(node))

inherited(node) 始终保存父节点当前的有效权限。即使节点处于 restricted 模式,这个字段也会随父节点继续更新;退出 restricted 后会立即使用最新 inherited。后代继承的是当前节点的有效权限,因此不会绕过中间的 restricted 边界。

例如:

read user:bob   on viking://resources/A
write group:engineering on viking://resources/A/B
read user:carol on viking://resources/A/B/C/report.md

report.md 的有效权限为:

  • Bob:read

  • engineering 的成员:write

  • Carol:read

如果把 A/B 设为 restricted,Bob 在 A 上的权限不会对 A/B 及其后代生效,但保存的 inherited 不会被删除。删除 restricted 后,Bob 会立即恢复从 A 继承的权限。

默认行为与 acl_mode

账号级 acl.enabled 默认关闭。关闭时,共享资源继续使用原有 URI namespace 可见性和写入规则,不解析或校验 ACL,也不为新建内容写入 ACL。

开启后,新建共享文件或目录的创建者会在首条 context 记录上获得直接 manage; 父目录权限作为继承 ACL 合并。已有且未设置 ACL 的内容不会迁移或改权,仍按公开 规则访问;重新关闭后,已有 ACL 也不再参与访问判断。add-resource 只把本次生成 的根目录(no_split 时为根文件)作为创建节点:根节点获得创建者直接 manage, 内部节点只继承,不重复写直接授权。重新向量化或覆盖已有 context 不会改变直接 ACL。

acl_mode 表示当前资源如何使用 ACL,与账号总开关 acl.enabled 不是一回事:

  • none:该资源不受 ACL 控制,沿用原有可见性规则。

  • inherit:使用直接权限和父目录传下来的权限。

  • restricted:只使用直接权限,但仍保存并更新父目录传下来的权限。

manage 权限的用户可以切换 inherit / restricted,不能直接设置 none 绕过父目录权限。退出 restricted 且没有直接权限、父目录也不受 ACL 控制时,系统会恢复为 none。restricted 节点即使没有直接权限也不会变公开,其没有单独授权的后代同样不可访问;账号管理员仍有隐式管理权。

文件操作

所有文件接口使用同一套权限判断:

操作所需能力
read、stat、list、tree、find、search、grep、glob、relationsread
write、create、mkdir、set tagswrite
删除或移动文件write
删除或移动目录目录及完整子树的 manage
管理 ACLmanage
move 目标父目录write

服务端会先 canonicalize URI,再在同一个鉴权入口中依次执行 account/owner/actor peer 等硬边界、有效 ACL 或 legacy fallback,以及写入和删除的 namespace 防护。

账号开启 acl.enabled 时,新建共享节点由创建者的直接 manage 完成权限 bootstrap,后续 ACL 修改要求有效 manage 能力。

目录上的 ACL 授权会被所有后代继承。listtree 和批量结果仍逐个检查有效 ACL,因为未设置 ACL 的目录可能按原有 URI 规则可见,而某个后代已经通过自己的 ACL 进入控制域。

共享区内部移动时,节点自己的 direct ACL 和 restricted 状态随节点移动,inherited 按新父节点重新计算。个人资源移入共享区时不携带 ACL,只继承目标目录权限;共享资源移回个人区时清空 ACL。

递归修改 tags、删除或移动目录会先校验完整目标子树。任一节点缺少所需能力,或子树扫描不完整,操作都会整体中止。

目录 statcount 使用相同的路径和 ACL 标量过滤,表示当前用户可见的 context 数量。

检索过滤

ACL 只保存在 context collection。每条 context 记录维护当前节点和继承权限两组原生标量字段:

acl_mode
acl_direct_grants
acl_inherited_grants

acl_direct_grants 是当前节点直接 ACL,acl_inherited_grants 是父节点当前有效 ACL,acl_mode 决定 inherited 是否参与当前节点的有效权限。每个 principal 只保存最高 level,编码为 {mask}:{principal}1 表示 read3 表示 write7 表示 manage。不维护独立 ACL collection。

请求的可用 principal 为 user:{ctx.user_id}user:*,以及 ctx.group_ids 中每个 ID 对应的 group:{group_id}。检索在共享区内用 acl_mode IN [inherit, restricted] 判断受控资源,再匹配各 principal 的 137 grant token:inherit 匹配 direct 或 inherited,restricted 只匹配 direct。旧记录字段缺失、为 nullnone 时仍走原有可见性规则,不会因空值漏检,也不会被当作 ACL 已开启。个人资源始终按 URI owner 隔离。

检索 target URI 只是搜索范围,不要求调用者能够读取 target 节点本身。用户即使不能读取中间目录,也可以检索到深层单独授权给自己的文件。

账号开启 acl.enabled 时,共享区 context 写入会保留同 URI 已有 direct ACL; 新创建节点为创建者生成直接 manage,并从父节点生成 inherited ACL。 add-resource 的内部节点只继承导入根节点。重新向量化和普通覆盖写不会把受控记录 恢复为默认可见,也不能通过普通 context 字段直接改 ACL。账号关闭该开关时,检索 只使用原有 account 和 URI scope 过滤,不使用这些 ACL 字段。

示例

将目录授权给 Bob 只读:

ov acl grant viking://resources/project-a --principal user:bob --level read

Bob 可以读取和检索该目录的后代,但不能写入或删除。升级为 write

ov acl grant viking://resources/project-a --principal user:bob --level write

删除 Bob 在当前节点上的直接授权:

ov acl revoke viking://resources/project-a --principal user:bob

如果 Bob 仍被祖先目录授权,该继承权限继续有效。

只使用当前节点直接授权,同时保留并继续更新继承字段:

ov acl set viking://resources/project-a --acl-mode restricted

相关文档

OpenViking 核心原理 / 16-资源访问控制 0 0 cosolar
2026-09-09T10:44:26.109435126Z 2026-09-09T10:44:54.575045480Z