
WeKnora 文档权限管理实战一次请求如何走完全程的 RBAC 访问控制与多租户隔离【免费下载链接】WeKnoraOpen-source LLM knowledge platform: turn raw documents into a queryable RAG, an autonomous reasoning agent, and a self-maintaining Wiki.项目地址: https://gitcode.com/GitHub_Trending/we/WeKnoraWeKnora 是一个开源 LLM 知识平台让文档变成可查询的 RAG 知识库。当多个团队共用同一套知识库时怎么保证别家的文档绝不可见本文跟随一次 HTTP 请求的完整生命周期拆解 WeKnora 的文档权限管理链路JWT 与 API Key 双通道认证、空间级 RBAC 访问控制、查询层自动附加 tenant_id 过滤最后落到多租户数据隔离的令牌回收闭环。登录发令牌还是传 API Key中间件怎么认出你是谁先看问题。权限系统的第一道关卡不是你能做什么而是你是谁。WeKnora 里有两类调用方浏览器里登录的真人和脚本里拿着密钥的机器。两者的凭据形态完全不同如果中间件写两套逻辑路由配置很容易漏。认证中间件的做法是把识别收敛成三条固定通道按顺序尝试// Auth 中间件按固定顺序尝试三条通道 if isNoAuthAPI(path, method) { c.Next(); return } // 登录、注册等白名单接口 if user, err : userService.ValidateToken(ctx, bearer); err nil { authenticateJWTUser(c, user, tenantID) // 通道一JWT解析空间与角色 return } authenticateAPIKeyRequest(c, xAPIKey) // 通道二X-API-Key // 三通道全部未命中 → 返回 401JWT 通道服务真人登录成功后签出一对令牌短的 access_token 用于日常请求长的 refresh_token 用来续期令牌会落库登记支持后续撤销。API Key 通道服务机器请求头带上X-API-Key服务端反查出所属空间。值得注意的细节是API Key 路由门禁给每条路由单独声明策略未声明的路由对 API Key 默认拒绝fail-closed避免忘了加限制这种经典事故。两条通道殊途同归认证结果会被写进请求上下文为后面的角色判断和租户过滤做准备。怎么给路由挂角色门槛RequireRole 的接法认出身份后下一个问题是这个身份能不能碰这条路由这就是 RBAC 访问控制的用武之地。WeKnora 的空间成员有四级角色viewer contributor admin owner高角色继承低角色权限。角色检查集中在 RequireRole 中间件接法很直白——路由注册时声明最低角色即可// 路由声明最低角色访客进不了写操作的门 group.POST(/knowledge-bases/:id/knowledge, middleware.RequireRole(types.TenantRoleContributor, cfg), h.AddKnowledge)三个设计决定值得记住fail-closed 兜底如果上下文里没解析出角色读取方默认按viewer处理宁可直接拒绝也不放行。灰度开关配置项tenant.enable_rbac关闭时越权请求只记日志不拦截方便生产环境平滑上线开启后同样的代码开始真正返回 403。归属优于角色contributor 在自己创建的知识库里拥有完全控制权在别人的库里等同 viewer。资源表上的creator_id字段是归属判断的依据配合OwnedKBOrAdmin这类归属守卫写操作要求是创建者或至少 Admin。角色矩阵与归属模型的完整说明见空间 RBAC 文档。怎么为查询自动附加租户过滤角色只管操作级别真正的多租户数据隔离发生在数据访问层——而且它不需要业务代码记得加条件。关键动作发生在认证收尾处applyAuthSession 把身份一次性写入请求的两个读取面gin 键与 request context保证下游无论用哪种方式取都一致// 认证通过后统一写入供全链路共享 if s.TenantID ! 0 { set(types.TenantIDContextKey, s.TenantID) // 租户隔离的关键 } set(types.UserContextKey, s.User) set(types.TenantRoleContextKey, s.Role) // 空间内角色下游的 repository 层从这里取出 tenantID拼进每条 SQL。以知识库为例// 知识库的所有读取都强制带上租户条件 db.Where(id ? AND tenant_id ?, id, tenantID).First(kb) db.Where(tenant_id ?, tenantID).Find(kbs)这就是自动的含义租户 ID 不是前端传来的参数而是认证链路单方面注入的业务代码无法绕过。跨空间超级管理员是明确的例外需要CanAccessAllTenants标记且通过canAccessTenant门禁后才生效属于受控通道而非默认行为。登出时怎么把令牌作废旧权限的最后一环常常被忽略登出后旧令牌还该不该有效WeKnora 的令牌不是签出去就不管。用户服务维护一张令牌登记表access_token 与 refresh_token 分开标记类型。登出时调用RevokeToken把令牌状态置为已撤销之后即使签名仍有效、未过期ValidateToken校验登记状态后也会拒绝放行。refresh 换发新令牌时旧 refresh_token 同步作废形成滚动回收。配合较短的 access_token 有效期泄露窗口的影响被压到最小。至此一次请求走完了全程认证认出你是谁 → 角色判断你能做什么 → 查询过滤你能看什么 → 登出终止你的令牌。延伸阅读空间 RBAC 完整说明认证中间件源码角色检查中间件源码用户数据模型【免费下载链接】WeKnoraOpen-source LLM knowledge platform: turn raw documents into a queryable RAG, an autonomous reasoning agent, and a self-maintaining Wiki.项目地址: https://gitcode.com/GitHub_Trending/we/WeKnora创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考