Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
115 lines
5.0 KiB
Markdown
115 lines
5.0 KiB
Markdown
---
|
||
title: 空间RBAC说明
|
||
tags: [安全认证, RBAC, 权限, 多空间, 角色]
|
||
aliases: [RBAC, 角色权限, 空间角色, TenantRBAC]
|
||
source: RBAC说明.md
|
||
---
|
||
|
||
# 空间 RBAC 说明
|
||
|
||
本文档介绍 WeKnora 的**空间内权限控制(Workspace RBAC)**,包括角色矩阵、资源归属模型,以及它与 [共享空间](./共享空间说明.md) 的关系。
|
||
|
||
> 状态:已发布;由配置项 `tenant.enable_rbac` 控制,默认 `true`(强制鉴权)。
|
||
> 完整说明、灰度方案、Schema、路由守卫等参见 [`docs/RBAC说明.md`](../../RBAC说明.md)。
|
||
|
||
## 解决的问题
|
||
|
||
RBAC 引入前,只要通过 `X-API-Key` 或 JWT 认证成功,调用方在空间内基本等同管理员。一旦一个空间出现多名真人成员,就需要区分:
|
||
|
||
- 谁可以删除知识库、撤销 API Key;
|
||
- 谁可以编辑「自己」的 KB / Agent;
|
||
- 谁只读。
|
||
|
||
## 角色矩阵
|
||
|
||
| 角色 | 标识 | 关键能力 |
|
||
|------|------|----------|
|
||
| 只读 | `viewer` | 仅读 |
|
||
| 贡献者 | `contributor` | 可变更 `creator_id == 自己` 的资源;他人资源按 Viewer |
|
||
| 管理员 | `admin` | 可变更空间内任意资源;管理成员、共享基础设施 |
|
||
| Owner | `owner` | Admin + 可删空间;每个空间至少一位,可以有多位 |
|
||
|
||
层级 `viewer < contributor < admin < owner`,高角色继承低角色。
|
||
|
||
Owner 的数量约束是“至少一位”,而不是“只能一位”。系统允许同一空间存在多个活跃 Owner;降级或移除 Owner 时,只有会导致空间失去最后一位 Owner 的操作才会被拒绝。
|
||
|
||
### 鉴权层的例外
|
||
|
||
- **跨空间超管**:`enable_cross_tenant_access` 打开且账号 `CanAccessAllTenants=true`,通过 `X-Tenant-ID` 切换后等同 Admin。
|
||
- **API Key**:合成虚拟用户在所属空间内固定 Admin(删空间除外)。
|
||
- **孤儿空间自愈**:首位认证的真人自动晋升 Owner,避免 API Key-only 空间锁死。
|
||
|
||
## 资源归属
|
||
|
||
迁移 `000043` 在关键表加上 `creator_id`:
|
||
|
||
- `knowledge_bases.creator_id` —— 老数据回填为该空间的 Owner;
|
||
- `custom_agents.creator_id` + `runnable_by_viewer`(默认 `true`,允许 Viewer 在对话中调用)。
|
||
|
||
子资源沿 `chunk → knowledge → kb → creator_id` 链回溯。
|
||
|
||
由此得到两类守卫:
|
||
|
||
- **角色守卫**:只看角色,用于空间级基础设施(模型、向量库、IM 通道等)。
|
||
- **归属守卫**`OwnedXxxOrAdmin`:creator 或 Admin+ 二者其一即放行,用于具体资源写操作。
|
||
|
||
## 与共享空间的关系
|
||
|
||
| 维度 | 解决什么 | 主键 |
|
||
|------|---------|------|
|
||
| **空间 RBAC** | 同一空间内「你能对自己/别人/共享基础设施做什么」 | `tenant_members(user_id, tenant_id, role)` |
|
||
| **共享空间** | 跨空间「让别的空间的人也能用我的 KB / Agent」 | `organization_members` + 共享关系 |
|
||
|
||
两者**正交**:
|
||
|
||
- 共享空间不持有 KB / Agent,只记录「以何种权限共享到了哪个空间」;资源归属与 `creator_id` 不变;
|
||
- 一次对**他人共享过来**的 KB 的写操作,需要同时满足:共享时设了「可写」 + 你在该空间不是 Viewer + 源空间的 RBAC 仍然放行;
|
||
- API Key 跨空间访问**不会**带 Admin 光环——共享路径由 `organization_members.role` 决定,与 API Key 无关。
|
||
|
||
判定顺序见 `internal/middleware/kb_access.go`:
|
||
|
||
```text
|
||
KB 属于我当前空间?─是─► 走空间 RBAC(角色 + creator_id)
|
||
└─否─► KB 共享给我所在空间?─是─► 取 min(共享权限, 空间角色)
|
||
└─否─► 403 / 404
|
||
```
|
||
|
||
一句话:**空间 RBAC 是纵向的纵深防御,共享空间是横向的协作通道;跨空间写动作必须同时穿过两道闸口。**
|
||
|
||
## 配置
|
||
|
||
```yaml
|
||
tenant:
|
||
enable_rbac: true # false 则进入「仅记录不拦截」灰度窗口
|
||
enable_cross_tenant_access: false
|
||
auth:
|
||
registration_mode: self_serve # 或 invite_only
|
||
audit:
|
||
retention_days: 90 # 0 表示不清理
|
||
```
|
||
|
||
环境变量 `WEKNORA_TENANT_ENABLE_RBAC` / `WEKNORA_AUDIT_RETENTION_DAYS` 覆盖 YAML。`DISABLE_REGISTRATION=true` 等价于把 `registration_mode` 强制设为 `invite_only`。
|
||
|
||
## 审计
|
||
|
||
`audit_logs` 表记录:
|
||
|
||
- `rbac.member_added` / `removed` / `role_changed` / `left`
|
||
- `rbac.access_denied`(仅强制鉴权时;1 分钟滑动窗口去重)
|
||
|
||
每日后台 goroutine 清理超过 `audit.retention_days` 的旧行。
|
||
|
||
## 相关主题
|
||
|
||
- [共享空间说明](./共享空间说明.md) — 跨空间协作与共享,与 RBAC 正交
|
||
- [OIDC认证调用流程](./OIDC认证调用流程.md) — 多空间用户体系的认证入口
|
||
- [Lite与标准版区别](../项目概述/Lite与标准版区别.md) — Lite 单用户场景下 RBAC 实际不发挥作用
|
||
|
||
---
|
||
|
||
## 反向链接
|
||
|
||
- [Home](../Home.md) — Wiki 首页导航
|
||
- [共享空间说明](./共享空间说明.md) — 共享空间访问最终落到空间 RBAC 校验
|
||
- [OIDC认证调用流程](./OIDC认证调用流程.md) — JWT 解析后即进入 RBAC 角色匹配
|