OpenViking 多租户架构实战:account/user 身份边界、认证模式与集成模式详解
本文围绕 OpenViking 的多租户能力展开,讲解其"单实例服务多团队/多客户"的身份隔离模型、
api_key与trusted两种认证模式、存储层的自动 account 前缀机制,以及 OpenClaw 插件与 Vikingbot 两种典型集成实践的取舍。读完本文,你将掌握通过root_api_key启用正式多租户、使用 Admin API 管理账户与用户、为日常数据访问签发并轮换 user key,以及依据业务形态选择正确多租户模式的方法。
一、多租户是什么:不是"每团队一套独立服务器"
OpenViking 的多租户并不等同于"为每个团队部署一套相互隔离的服务器"。它的设计主张是:一个 OpenViking Server 进程,通过 account 与 user 两级身份边界,来控制数据共享与隔离。这一模型恰好覆盖两类典型场景:
- 多团队/多客户共享一套服务:不同团队或客户的数据必须互相隔离;
- 团队内多用户:团队成员需要共享资源,但各自的记忆(memories)保持隔离。
启用多租户后,单个 Server 即可:
- 同时服务多个团队、客户或应用;
- 用
account隔离不同团队; - 在同一
account内默认共享resources,并可通过 ACL 做目录级/文件级授权; - 用
user隔离用户记忆与会话; - 以 ROOT / ADMIN / USER 三级角色管理权限;
- 支持 OpenClaw 插件、Vikingbot、CLI、HTTP SDK 等多种集成形态。
二、核心身份模型:account / user / role
2.1 account_id:外层租户边界
account 可以理解为工作区(workspace)、团队或客户空间:
- 不同
account之间的数据默认完全隔离; - 只有 ROOT 能创建和删除
account; resources、user、session都归属某个account内部。
从源码看,RequestContext 直接由 UserIdentifier(account_id, user_id) 构造,account_id 贯穿 Router → Service → VikingFS 全链路(见 openviking/server/identity.py),这正是"请求上下文"驱动隔离的实现基础。
2.2 user_id:账户内用户边界
- 用户记忆、用户会话按
user_id隔离; - 普通用户只能访问自己的用户空间;
- 同
account内的 admin 可以管理用户。
2.3 三级角色
| 角色 | 作用域 | 典型能力 |
|---|---|---|
| ROOT | 全局 | 创建/删除 account、跨租户访问、用户管理 |
| ADMIN | 单个 account | 管理同 account 内的用户、重新生成用户 key |
| USER | 单个 account | 访问自己的 user/peer/session 数据以及同 account 内共享资源 |
角色在 openviking/server/identity.py 中被定义为一个带权限等级(rank)的类型:USER=0、ADMIN=1、ROOT=2,同时支持 Role.register(name, rank) 动态注册自定义角色。
三、两种多租户认证模式
| 模式 | 配置 | 身份来源 | 典型场景 |
|---|---|---|---|
api_key |
server.auth_mode = "api_key" |
Root key 或 user key | 标准部署 |
trusted |
server.auth_mode = "trusted" |
上游注入的 X-OpenViking-Account / X-OpenViking-User |
位于可信网关之后 |
在 trusted 模式下,上游网关还可以断言 X-OpenViking-Role: user 或 X-OpenViking-Role: admin。角色断言要求配置了 root_api_key 且请求携带匹配的 API key;X-OpenViking-Role: root 会被拒绝——ROOT 保留给经过校验的 Admin API 回退路径。
3.1 root_api_key 的作用
一旦配置 server.root_api_key,OpenViking 即进入正式多租户模式:
- Root key 负责管理账户与用户;
- User key 由 Admin API 生成,供普通数据访问使用;
- 服务器从 user key 解析出
account_id、user_id和角色。
反过来,若 auth_mode = "api_key" 但未配置 root_api_key,服务器运行在 dev 模式:
- 所有请求按 ROOT 处理;
- 默认身份是
default/default; - 仅允许在 localhost 上运行。
结合 docs/en/guides/04-authentication.md 的说明:如果 auth_mode 未显式配置,配置了非空 root_api_key 时自动选择 api_key 模式,否则自动选择 dev 模式;把 root_api_key 设为空字符串 "" 是非法配置。
四、共享与隔离边界
4.1 逻辑层
| 数据类型 | 跨 account 共享 | account 内共享 | 默认隔离边界 |
|---|---|---|---|
共享资源(viking://resources) |
否 | 默认共享,ACL 可限制 | account / ACL |
用户资源(viking://user/{user_id}/resources) |
否 | 否 | user |
Peer 资源(viking://user/{user_id}/peers/{peer_id}/resources) |
否 | 否 | user / peer |
| 记忆(Memories) | 否 | 否 | user / peer |
| 技能(Skills) | 否 | 否 | user |
| 会话(Sessions) | 否 | 否 | user / session |
4.2 存储层:隐藏的 account 前缀
对用户而言,URI 看起来仍然是普通的 viking://... 路径:
viking://resources/project-a/
viking://user/alice/memories/
viking://user/alice/resources/
viking://user/alice/peers/web-visitor-alice/resources/
但底层存储会自动加上 account 前缀:
/local/{account_id}/resources/project-a/
/local/{account_id}/user/alice/memories/
/local/{account_id}/user/alice/resources/
/local/{account_id}/user/alice/peers/web-visitor-alice/resources/
所以多租户隔离并不依赖特殊的公共 URI 格式,而是依赖请求上下文中的 account_id 与 user_id,并贯穿整个技术栈一致地生效。例如在删除账户时,openviking/server/routers/admin.py 会级联清理 AGFS 数据(/local/{account_id} 目录)与 VectorDB 记录,最后才删除账户元数据。
4.3 文件系统与检索层
文件系统操作与语义检索都是租户感知(tenant-aware)的:
- 非 ROOT 请求自动按
account_id过滤; resources默认包含 account 共享资源,配置了 ACL 时使用有效 ACL;- 用户资源始终限定在当前用户空间;需要共享就把它们移到
viking://resources; memory与skill仍按当前用户空间过滤;- actor peer 会在文件系统与检索操作中把
viking://user/{user}/peers过滤到单个 peer。
这套机制保证了"能搜到的 = 能读到的"。
4.4 Peer 集合过滤(Peer Collection Filter)
peer_id 是当前用户边界内的内容作用域,它从不改变租户或用户身份。当请求只需要看到当前用户 peer 集合中的某一个 peer 时,可设置:
X-OpenViking-Actor-Peer: <peer_id>
(或通过 SDK/CLI 的 actor_peer_id 参数),其效果如下:
- 空目标检索仍包含当前用户根目录与共享的
viking://resources; - 当检索解析
viking://user/{user}/peers时,只选中该 peer 的记忆/资源; - 文件系统操作无法对
viking://user/{user}/peers下其他 peer 进行读取、list/tree、grep/find/search、写入、移动或删除; - 用户范围的记忆、资源、技能、共享资源与会话归属保持不变;
- peer ID 必须是安全的单路径段,例如
web-visitor-alice。
从实现上看,actor_peer_id 是 RequestContext 的一个字段(openviking/server/identity.py),并广泛作用于命名空间解析与检索目标构建(见 openviking/core/namespace.py、openviking/core/retrieval_targets.py)。
五、标准使用流程
步骤 1:启用多租户
{
"server": {
"auth_mode": "api_key",
"root_api_key": "your-secret-root-key"
}
}
步骤 2:ROOT 创建 account 与首个 admin
curl -X POST http://localhost:1933/api/v1/admin/accounts \
-H "Content-Type: application/json" \
-H "X-API-Key: your-secret-root-key" \
-d '{
"account_id": "acme",
"admin_user_id": "alice"
}'
响应中会携带 alice 的 user_key(Admin API 实现见 openviking/server/routers/admin.py)。
步骤 3:ADMIN 或 ROOT 注册普通用户
curl -X POST http://localhost:1933/api/v1/admin/accounts/acme/users \
-H "Content-Type: application/json" \
-H "X-API-Key: <admin-or-root-key>" \
-d '{
"user_id": "bob",
"role": "user"
}'
步骤 4:普通应用流量优先使用 user key
curl http://localhost:1933/api/v1/fs/ls?uri=viking:// \
-H "X-API-Key: <bob-user-key>"
这样服务器可以直接从 key 解析身份,无需额外的租户头。
步骤 5:数据 API 身份来自 user/admin key
在 api_key 模式下,ls、find、sessions 等租户范围数据 API 从 API key 本身解析有效的 account 与 user。此模式下不要发送 X-OpenViking-Account 或 X-OpenViking-User——基于 header 的身份断言属于 trusted 模式。
- ADMIN key 可以以自身 account/user 调用数据 API(如
ls viking://); - ROOT key 只用于 Admin API 和少量系统/监控 API,因为它不绑定租户用户,在
api_key模式下无法访问租户范围的数据 API。数据访问请用 user/admin key,或改用 trusted 模式做上游身份断言。
完整演练:Admin 工作流示例
仓库的 examples/multi_tenant 目录提供了一个端到端的完整示例,包含配置模板、Python SDK 脚本和 CLI 脚本,覆盖以下流程:
1. Health Check 无需认证,验证服务可用
2. Create Account ROOT 创建 account "acme",同时创建首个 admin "alice"
3. Register User (ROOT) ROOT 在 "acme" 下注册普通用户 "bob"
4. Register User (ADMIN) alice (ADMIN) 在 "acme" 下注册用户 "charlie"
5. List Accounts ROOT 列出所有 account
6. List Users 列出 "acme" 下所有用户及角色
7. Change Role ROOT 将 bob 提升为 ADMIN
8. Regenerate Key 为 charlie 重新生成 key,旧 key 立即失效
9. Access Data bob 使用 user key 访问数据
10. Error Tests 非法 key、权限不足、重复创建、旧 key 等负面用例
11. Remove User 删除 charlie,验证其 key 失效
12. Delete Account 删除 account "acme",验证 alice 的 key 也失效
运行方式:
# Python SDK(依赖 uv)
uv sync
uv run admin_workflow.py --url http://localhost:1933 --root-key my-root-key
# CLI 脚本
ROOT_KEY=my-root-key SERVER=http://localhost:1933 bash admin_workflow.sh
服务端配置文件模板见 examples/multi_tenant/ov.conf.example,其中 server.root_api_key 即为启用多租户认证的关键项。注意该示例同时配置了 embedding 与 VLM 的 API Key,你需要填入自己的密钥。
六、Admin API 与 CLI 命令参考
6.1 Admin API 端点
| 方法 | 端点 | 所需角色 | 说明 |
|---|---|---|---|
| POST | /api/v1/admin/accounts |
ROOT | 创建 account + 首个 admin |
| GET | /api/v1/admin/accounts |
ROOT | 列出所有 account |
| DELETE | /api/v1/admin/accounts/{id} |
ROOT | 删除 account(级联清理存储) |
| POST | /api/v1/admin/accounts/{id}/users |
ROOT, ADMIN | 注册用户 |
| GET | /api/v1/admin/accounts/{id}/users |
ROOT, ADMIN | 列出用户 |
| DELETE | /api/v1/admin/accounts/{id}/users/{uid} |
ROOT, ADMIN | 移除用户 |
| PUT | /api/v1/admin/accounts/{id}/users/{uid}/role |
ROOT | 修改用户角色(源码中目前仅支持提升为 ADMIN,见 openviking/server/routers/admin.py) |
| POST | /api/v1/admin/accounts/{id}/users/{uid}/key |
ROOT, ADMIN | 重新生成 user key(旧 key 立即失效) |
6.2 CLI 命令
# Account 管理
openviking admin create-account <account_id> --admin <admin_user_id>
openviking admin list-accounts
openviking admin delete-account <account_id>
# User 管理
openviking admin register-user <account_id> <user_id> [--role user|admin]
openviking admin list-users <account_id>
openviking admin remove-user <account_id> <user_id>
openviking admin set-role <account_id> <user_id> <role>
openviking admin regenerate-key <account_id> <user_id>
此外,在 ovcli.conf 中同时配置 api_key 与 root_api_key 后,可用 ov --sudo 执行管理命令:
{
"url": "http://localhost:1933",
"api_key": "<user-key>",
"root_api_key": "<root-key>"
}
ov --sudo admin list-accounts
ov --sudo reindex viking://
ov --sudo system status
--sudo 仅对 admin、system、reindex 这类管理/系统命令生效,并且要求 ovcli.conf 中配置了 root_api_key。
七、两种典型集成模式
7.1 OpenClaw 插件:一个实例持有一个 user key
当前 OpenClaw 插件遵循"插件持有单一用户身份"的模型:
- 远程模式配置为
baseUrl + apiKey,可选peer_role/peer_prefix; apiKey通常应为 user key;- 服务器从该 user key 解析
account_id与user_id; - 插件把 OpenClaw agent 身份放在 peer/session 元数据中,而不是租户 header 中。
典型配置:
openclaw config set plugins.entries.openviking.config.mode remote
openclaw config set plugins.entries.openviking.config.baseUrl "http://your-server:1933"
openclaw config set plugins.entries.openviking.config.apiKey "<user-api-key>"
openclaw config set plugins.entries.openviking.config.peer_role assistant
openclaw config set plugins.entries.openviking.config.peer_prefix "<peer-prefix>"
该模型的特点:
- 集成简单——插件不管理 account/user 生命周期;
- 最适合"一个 OpenClaw 实例映射到一个 OpenViking 用户身份";
peer_prefix用于构建 peer/session 元数据时区分不同 OpenClaw 运行时身份;- 同 account 内
resources默认共享、可用 ACL 限制,用户记忆保持 user 级隔离。
为什么插件通常不设置 account / user:在 api_key 模式下 user key 已经足够表达身份——account 和 user 由服务器端从 key 解析,插件只需用 peer_prefix 做运行时身份标注,内部写用户级记忆、用 peer_id 标识每条消息的发言者。如果直接把 root key 给插件,普通租户范围数据 API 将无法获得 key 绑定的租户用户,这不是日常访问的好默认值。
7.2 Vikingbot:root key 管理大量终端用户
Vikingbot 的做法不同——它更像一个服务大量终端用户的平台:
- 机器人用 root key 连接 OpenViking;
- 机器人配置中固定一个
account_id; - 机器人自动在该 account 内注册用户;
- 机器人缓存每个用户的 user key,并在记忆提交/搜索时尽可能使用 user key。
示例配置:
{
"bot": {
"ov_server": {
"server_url": "http://127.0.0.1:1933",
"root_api_key": "test",
"account_id": "default",
"admin_user_id": "default"
}
}
}
该模型的特点:
- 适合一个 bot 服务服务大量聊天用户;
- 同 account 内
resources默认共享,ACL 可细化到具体目录或文件的访问; - 用户记忆通过自动管理的用户身份实现隔离;
- 相比 OpenClaw 插件,bot 承担了更多租户生命周期管理逻辑。
7.3 如何选择
| 场景 | 推荐模式 |
|---|---|
| 一个 OpenClaw 实例映射到一个固定身份 | OpenClaw 插件 + user key |
| 一个网关或 bot 服务大量终端用户 | Vikingbot + root-key 管理用户 |
| 可信网关在上游注入身份 | trusted 模式 |
| 本地单用户体验、无需正式租户隔离 | 不配置 root_api_key 的 dev 模式 |
八、常见误区
1. root_api_key 不是日常业务访问 key
Root key 主要用于:创建/删除 account、注册用户、重新生成 key、运维与诊断。日常应用流量应根据调用者身份使用 user key 或 admin key。
2. peer_id 不定义租户
peer_id 标识当前用户下的某个交互 peer,它不创建租户,但可以通过显式 peer URI 或 peer 集合过滤来圈选 peer 内容,例如:
viking://user/{user_id}/peers/{peer_id}/memories
viking://user/{user_id}/peers/{peer_id}/resources
租户边界是 account_id,用户边界是 user_id,peer 内容始终停留在该用户边界之内。
3. 没有 root_api_key 不等于"正式的单租户生产模式"
那只是 dev 模式:所有请求以 ROOT 运行,不适合公开或共享部署。从 docs/en/guides/04-authentication.md 可知,dev 模式下服务器仅允许绑定 localhost,绑定到非回环地址(如 0.0.0.0)会拒绝启动。
4. OpenClaw 插件与 Vikingbot 不是同一种多租户模式
- OpenClaw 插件 ≈ "客户端直接使用一个用户身份";
- Vikingbot ≈ "平台管理大量用户及其 user key"。
九、延伸阅读
- 认证指南 — 认证模式、header 与 key 规则(含 OIDC/LDAP)
- 配置指南 —
root_api_key与auth_mode配置项 - Admin API 参考 — Admin API 完整参考
- API 概览 — CLI 与 HTTP 连接方式
- 资源访问控制(ACL) — account 内资源授权、继承与检索过滤
- ACL API — HTTP、SDK、CLI 接口
- 数据加密 — 多租户部署中的静态加密
- 多租户完整示例 — 端到端管理流程
- OpenClaw 插件 — OpenClaw 集成
- Vikingbot — bot 侧多用户集成
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
video-shotcraftAI宣传片skill,使用 Remotion 制作电影级产品视频:提供106 张镜头配方卡和可复用的视频魔板。适用于 Claude Code 与 Codex以及所有其他智能体Markdown00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00