fix(oidc): 同步认证中心用户资料到本地用户

从已验证的 OIDC Claim 提取用户名、显示名称、邮箱、手机号和头像,并覆盖单租户、多租户及平台用户的 JIT 创建与重复登录同步。\n\n保留 metadata.manualProfile 标记下的人工资料,限制字段长度且仅接收已验证联系方式与 HTTPS 头像。已通过 auth、httpapi、store 测试及临时 PostgreSQL 集成验证。
This commit is contained in:
2026-08-03 15:55:50 +08:00
parent 3c8d9839a4
commit b125599354
10 changed files with 206 additions and 24 deletions
@@ -91,9 +91,15 @@ func (s *Store) resolveOrProvisionOIDCMultiTenantUser(ctx context.Context, input
}
rolesJSON, _ := json.Marshal(input.Roles)
user, err = scanUser(tx.QueryRow(ctx, `UPDATE gateway_users SET
username=COALESCE(NULLIF($2,''),username),roles=$3::jsonb,last_login_at=now(),synced_at=now(),source_updated_at=now(),updated_at=now()
username=COALESCE(NULLIF($2,''),username),
display_name=CASE WHEN metadata->>'manualProfile'='true' THEN display_name ELSE COALESCE(NULLIF($3,''),display_name) END,
email=CASE WHEN metadata->>'manualProfile'='true' THEN email ELSE COALESCE(NULLIF($4,''),email) END,
phone=CASE WHEN metadata->>'manualProfile'='true' THEN phone ELSE COALESCE(NULLIF($5,''),phone) END,
avatar_url=CASE WHEN metadata->>'manualProfile'='true' THEN avatar_url ELSE COALESCE(NULLIF($6,''),avatar_url) END,
roles=$7::jsonb,last_login_at=now(),synced_at=now(),source_updated_at=now(),updated_at=now()
WHERE id=$1::uuid AND source='oidc_v2' AND status='active' AND deleted_at IS NULL
RETURNING `+userColumns, user.ID, input.Username, string(rolesJSON)))
RETURNING `+userColumns, user.ID, input.Username, input.DisplayName, input.Email,
input.Phone, input.AvatarURL, string(rolesJSON)))
if err != nil {
return ResolveOrProvisionOIDCUserResult{}, err
}
@@ -203,13 +209,16 @@ func (s *Store) createOIDCMultiTenantUser(ctx context.Context, tx pgx.Tx, bindin
rolesJSON, _ := json.Marshal(input.Roles)
metadata, _ := json.Marshal(map[string]any{"provisioningMode": "oidc-multi-tenant-jit"})
user, err := scanUser(tx.QueryRow(ctx, `INSERT INTO gateway_users(
user_key,source,external_user_id,username,gateway_tenant_id,tenant_id,tenant_key,
user_key,source,external_user_id,username,display_name,email,phone,avatar_url,
gateway_tenant_id,tenant_id,tenant_key,
default_user_group_id,roles,auth_profile,metadata,status,last_login_at,synced_at,source_updated_at
) VALUES($1,'oidc_v2',NULL,$2,$3::uuid,$4,$5,$6::uuid,$7::jsonb,'{}'::jsonb,$8::jsonb,
) VALUES($1,'oidc_v2',NULL,$2,NULLIF($3,''),NULLIF($4,''),NULLIF($5,''),NULLIF($6,''),
$7::uuid,$8,$9,$10::uuid,$11::jsonb,'{}'::jsonb,$12::jsonb,
'active',now(),now(),now())
ON CONFLICT(user_key) DO UPDATE SET updated_at=gateway_users.updated_at
RETURNING `+userColumns,
userKey, username, gatewayTenantID, input.TenantID, tenantKey, groupID, string(rolesJSON), string(metadata),
userKey, username, input.DisplayName, input.Email, input.Phone, input.AvatarURL,
gatewayTenantID, input.TenantID, tenantKey, groupID, string(rolesJSON), string(metadata),
))
if err != nil {
return GatewayUser{}, "", false, err