feat(gateway): 多租户增量2 —— gorm 租户插件按上下文自动隔离查询(SaaS P1)

统一强制、别靠人肉:受租户模型标记 isTenantScoped() 后,store/tenant_scope.go
的 gorm 回调按请求 ctx 自动给查询加 WHERE tenant_id、创建自动填 tenant_id。
- KB / Agent 加 TenantID 字段 + isTenantScoped() 标记
- middleware.TenantContext 把 tenant 注入 request context 供 store 插件读取
- ctx 无租户(系统/回填/未登录)不过滤,保留跨租户操作能力
- 启动 BackfillRowTenants 回填存量行 tenant_id=owner 默认租户(幂等)

live 验证:创建自动写 tenant_id ✓;同 owner 不同 tenant 的行被查询过滤 ✓。
Doc/DocLink(异步入库)、Task/Eval(无 owner)留待增量2b。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Blizzard
2026-07-06 17:58:58 +08:00
parent f7d12cbf66
commit 30d667954b
6 changed files with 116 additions and 9 deletions
@@ -20,6 +20,9 @@ func TenantContext(db *store.Postgres) gin.HandlerFunc {
if uid, _ := v.(string); uid != "" {
if t, err := db.EnsureDefaultTenant(c.Request.Context(), uid, ""); err == nil && t != nil {
c.Set(CtxTenantID, t.ID)
// 注入请求 contextstore 的 gorm 租户插件据此对受租户表自动加 tenant_id 过滤/填充。
// handler 须用 c.Request.Context() 调 store(现有代码已如此),隔离才会生效。
c.Request = c.Request.WithContext(store.WithTenant(c.Request.Context(), t.ID))
}
}
}