-
Notifications
You must be signed in to change notification settings - Fork 280
Open
Labels
enhancementNew feature or requestNew feature or request
Description
背景
OpenViking 当前为单租户架构:
- 认证:单一全局
api_key,HMAC 比对 - 无 RBAC:所有认证用户拥有完全访问权限
- 无存储隔离:所有数据共享同一命名空间
- 服务层:
OpenVikingService持有单例_user,不支持请求级用户上下文
需要实现多租户支持。Phase 1 聚焦 API 层能力定义,建立身份、认证、授权的基础框架,为 Phase 2 存储隔离做准备。
设计方案
设计文档:docs/design/multi-tenant-design.md
RFC 讨论:#157
两层 API Key 体系
| 类型 | 格式 | 解析方式 | 存储位置 |
|---|---|---|---|
| Root Key | 纯随机 token(secrets.token_hex(32)) |
HMAC 比对 | ov.conf server 段 root_api_key |
| User Key | 纯随机 token(secrets.token_hex(32)) |
查内存索引 | /{account_id}/_system/users.json |
- Key 无前缀,不携带身份信息
- 认证时顺序匹配:先 HMAC 比对 root key,再查 user key 索引,均不匹配则 401
三层 RBAC
| 角色 | 枚举值 | 能力 |
|---|---|---|
| ROOT | root |
一切:创建/删除工作区、提升用户角色、跨租户访问 |
| ADMIN | admin |
用户属性(非 Key 类型),管理本工作区用户、下发 User Key、工作区内全量数据访问 |
| USER | user |
访问自己的 user/agent/session/resources scope |
认证流程
- 从
X-API-Key或Authorization: Bearer提取 Key - 获取
app.state.api_key_manager;若为None(未配置root_api_key)→ dev 模式,返回固定 ROOT 身份(account_id="default", user_id="default") - HMAC 比对 root key → 匹配则返回
role=ROOT - 查 user key 内存索引 → 匹配则返回
(account_id, user_id, role=ADMIN/USER) - 均不匹配 → 401
- 从
X-OpenViking-Agentheader 读取agent_id(默认 "default") - 构造
RequestContext(UserIdentifier, Role)注入到 Router
存储结构
/_system/accounts.json # 全局工作区列表
/{account_id}/_system/users.json # Per-account 用户注册表(含 key 和 role)
Phase 1 边界
RequestContext在 Router 层注入,不向 Service/VikingFS 层传递(Phase 2 完成)- 存储路径不变,VectorDB schema 不变
- 嵌入模式原生支持多租户(调用方直接声明身份,无 API Key 认证)
任务拆解
T1: 身份与角色类型定义
新建 openviking/server/identity.py:
Role(str, Enum): ROOT / ADMIN / USERResolvedIdentity: 认证中间件输出(role, account_id?, user_id?, agent_id?),字段均为 OptionalRequestContext: 请求级上下文(UserIdentifier+Role),贯穿 Router → Service → VikingFS
T2: ServerConfig 更新
修改 openviking/server/config.py:
api_key→root_api_key(ROOT 身份认证)root_api_key为None时进入 dev 模式,不区分multi_tenant开关
T3: API Key Manager
新建 openviking/server/api_keys.py:
- 内存索引:
_user_keys: Dict[str, UserKeyEntry]实现 O(1) 查找 - 持久化:per-account
/{account_id}/_system/users.json+ 全局/_system/accounts.json resolve(api_key): HMAC 比对 root key → 查 user key 索引 → 401create_account/delete_account/register_user/remove_user/regenerate_key/set_role等管理方法
T4: 认证中间件重写
重写 openviking/server/auth.py:
resolve_identity(): 提取 Key → APIKeyManager 解析 → 返回ResolvedIdentity;无 api_key_manager 时返回 dev 模式默认身份get_request_context():ResolvedIdentity→RequestContext(Optional 字段填入 "default")require_role(*roles): 角色守卫工厂,用于 Admin API 权限检查
T5: App 初始化集成
修改 openviking/server/app.py:
root_api_key存在时:创建 APIKeyManager →load()→ 赋值app.state.api_key_managerroot_api_key为 None 时:app.state.api_key_manager = None(dev 模式)- Admin Router 始终注册
T6: Router 依赖注入迁移
修改所有 router(filesystem, content, search, resources, sessions, relations, pack, system, debug, observer):
Depends(verify_api_key)→Depends(get_request_context)- Phase 1 仅替换依赖注入,
_ctx接收但不向 service 层传递
T7: Admin Router
新建 openviking/server/routers/admin.py:
| 端点 | 方法 | 权限 | 功能 |
|---|---|---|---|
/api/v1/admin/accounts |
POST | ROOT | 创建工作区 + 首个 admin 用户 |
/api/v1/admin/accounts |
GET | ROOT | 列出所有工作区 |
/api/v1/admin/accounts/{account_id} |
DELETE | ROOT | 删除工作区 |
/api/v1/admin/accounts/{account_id}/users |
POST | ROOT, ADMIN | 注册用户 |
/api/v1/admin/accounts/{account_id}/users |
GET | ROOT, ADMIN | 列出工作区内用户 |
/api/v1/admin/accounts/{account_id}/users/{user_id} |
DELETE | ROOT, ADMIN | 移除用户 |
/api/v1/admin/accounts/{account_id}/users/{user_id}/role |
PUT | ROOT | 修改用户角色 |
/api/v1/admin/accounts/{account_id}/users/{user_id}/key |
POST | ROOT, ADMIN | 重新生成 user key |
ADMIN 仅能操作自己所属的 account。
T8: 客户端 SDK 更新
- HTTP 客户端移除
account_id/user_id参数,身份由服务端从 API Key 解析 - 新增
agent_id参数,通过X-OpenViking-Agentheader 发送 - CLI 新增 admin 命令组
- Rust CLI 新增 admin 子命令
T9: 文档更新
- 新增中英文 Admin API 文档
- 更新认证指南、配置指南、部署指南
- 新增多租户示例 (
examples/multi_tenant/)
T10: 测试
- APIKeyManager 单元测试(key 生成/解析/注册检查)
- 认证中间件测试(root key、user key、dev 模式、require_role 守卫)
- Admin API 集成测试
- 身份模块单元测试
- 回归测试(现有测试适配 dev mode)
关联
- Phase 2 实施:Phase 2 Issue 将在创建后关联
- 设计讨论:RFC: Multi-Tenant Design #157
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request
Type
Projects
Status
In progress