feat(identity): 接入认证中心多租户登录

支持 Manifest V2 动态 tid 验证、Tenant Context 同步和租户内 JIT 投影,并保留 Manifest V1 与旧 Session 兼容。\n\n增加 tenantHint、租户切换、普通注册关闭及 application/principal/tenant 两级 SSF 撤销;迁移、定向安全测试和本地双租户跨仓 E2E 已通过。\n\nrelease_required=true;未执行 Release、Staging 或真实链路。
This commit is contained in:
2026-07-28 17:28:35 +08:00
parent 0b02e62c72
commit 5c679ff13f
45 changed files with 2986 additions and 139 deletions
+29 -9
View File
@@ -8,6 +8,7 @@ import (
"errors"
"fmt"
"strings"
"time"
"github.com/easyai/easyai-ai-gateway/apps/api/internal/auth"
"github.com/jackc/pgx/v5"
@@ -20,15 +21,24 @@ var (
)
type ResolveOrProvisionOIDCUserInput struct {
Issuer string
Subject string
Username string
Roles []string
TenantID string
GatewayTenantKey string
ProvisioningEnabled bool
RequestIP string
UserAgent string
Issuer string
ApplicationID string
Subject string
Username string
Roles []string
TenantID string
TenantMode string
TenantName string
TenantSlug string
TenantMetadataStatus string
TenantMetadataVersion string
TenantMetadataETag string
TenantMetadataUpdatedAt time.Time
OIDCClientID string
GatewayTenantKey string
ProvisioningEnabled bool
RequestIP string
UserAgent string
}
type ResolveOrProvisionOIDCUserResult struct {
@@ -48,6 +58,9 @@ type oidcUserProjection struct {
func (s *Store) ResolveOrProvisionOIDCUser(ctx context.Context, input ResolveOrProvisionOIDCUserInput) (ResolveOrProvisionOIDCUserResult, error) {
input = normalizeOIDCUserInput(input)
if input.TenantMode == "multi_tenant" {
return s.resolveOrProvisionOIDCMultiTenantUser(ctx, input)
}
if input.Issuer == "" || input.Subject == "" || input.TenantID == "" {
return ResolveOrProvisionOIDCUserResult{}, errors.New("invalid OIDC user projection input")
}
@@ -296,6 +309,13 @@ func normalizeOIDCUserInput(input ResolveOrProvisionOIDCUserInput) ResolveOrProv
input.Subject = strings.TrimSpace(input.Subject)
input.Username = strings.TrimSpace(input.Username)
input.TenantID = strings.TrimSpace(input.TenantID)
input.ApplicationID = strings.TrimSpace(input.ApplicationID)
input.TenantMode = strings.TrimSpace(input.TenantMode)
input.TenantName = strings.TrimSpace(input.TenantName)
input.TenantSlug = strings.TrimSpace(input.TenantSlug)
input.TenantMetadataStatus = strings.TrimSpace(input.TenantMetadataStatus)
input.TenantMetadataVersion = strings.TrimSpace(input.TenantMetadataVersion)
input.TenantMetadataETag = strings.TrimSpace(input.TenantMetadataETag)
input.GatewayTenantKey = strings.TrimSpace(input.GatewayTenantKey)
input.RequestIP = strings.TrimSpace(input.RequestIP)
input.UserAgent = strings.TrimSpace(input.UserAgent)