Files
xinmi/docs/wiki/安全认证/RBAC说明.md
T
yawan f7fc992f57
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
WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
2026-09-22 16:19:06 +08:00

115 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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 角色匹配