feat(gateway): 多租户地基·增量1 —— 租户身份/成员/上下文(T4.A/SaaS P1)
按 SAAS_DESIGN.md P1 第一刀(真·多租户 + 桌面端为主):先立租户身份,不动查询。 - store.Tenant / TenantMember 表 + AutoMigrate - store: CreateTenant / AddMember(幂等) / DefaultTenantForUser / EnsureDefaultTenant(幂等) / BackfillDefaultTenants / GetTenant / MemberRole - 注册即建单人默认租户(owner);启动回填给存量用户补建(幂等) - middleware.TenantContext(挂 Auth 后)解析当前租户→注入 tenant_id;handler.tenantID(c) 助手 - GET /api/v1/tenants/current 验证端点(租户上下文 + 角色) - live:存量用户(回填 7 租户)/tenants/current 返回默认租户+owner;新注册自动建租户 下一步(增量2):核心表加 tenant_id + 统一 gorm scope 强制隔离 + 存量行回填 + 重写查询。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ package handler
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
@@ -11,6 +12,13 @@ import (
|
||||
"github.com/sundynix/sundynix-gateway/internal/store"
|
||||
)
|
||||
|
||||
func firstNonEmpty(a, b string) string {
|
||||
if a != "" {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// userJSON 是对外的用户视图(绝不含密码哈希)。
|
||||
func userJSON(u *store.User) gin.H {
|
||||
return gin.H{"id": u.ID, "email": u.Email, "name": u.Name}
|
||||
@@ -46,6 +54,10 @@ func (h *Handler) Register(c *gin.Context) {
|
||||
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
// 多租户:每个新用户建一个单人默认租户(owner)。失败不阻断注册(中间件会兜底补建)。
|
||||
if _, e := h.db.EnsureDefaultTenant(c.Request.Context(), u.ID, firstNonEmpty(strings.TrimSpace(body.Name), email)); e != nil {
|
||||
log.Printf("[auth] 建默认租户失败 uid=%s: %v", u.ID, e)
|
||||
}
|
||||
issueToken(c, u)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user