Files
sundynix-agentix/sundynix-gateway/internal/middleware/tenant.go
T
Blizzard 30d667954b 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>
2026-07-06 17:58:58 +08:00

32 lines
1.3 KiB
Go
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.
package middleware
import (
"github.com/gin-gonic/gin"
"github.com/sundynix/sundynix-gateway/internal/store"
)
// CtxTenantID 是鉴权后写入 gin.Context 的当前租户 ID 键。
const CtxTenantID = "tenant_id"
// TenantContext 解析当前用户的默认租户并注入 tenant_id(多租户作用域的事实源)。
// 须挂在 Auth 之后(依赖已注入的 uid);未登录请求跳过。存量/异常无租户者由 EnsureDefaultTenant
// 幂等兜底补建,保证任何已登录请求都能拿到 tenant_id。
//
// 注:当前每请求解析一次(1–2 条按索引查询)。后续可把 tenant_id 嵌入 JWT / 加缓存去掉此开销。
func TenantContext(db *store.Postgres) gin.HandlerFunc {
return func(c *gin.Context) {
if v, ok := c.Get(CtxUserID); ok {
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))
}
}
}
c.Next()
}
}