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:
@@ -85,6 +85,12 @@ func (s *Service) Create(ctx context.Context, bundle TokenBundle, localUser *aut
|
||||
if err != nil || verified == nil || verified.Source != "oidc" || verified.ID == "" || verified.ID != localUser.ID {
|
||||
return "", ErrSessionInvalid
|
||||
}
|
||||
if localUser.OIDCUserBindingID != "" &&
|
||||
(localUser.Issuer == "" || localUser.ApplicationID == "" || localUser.TenantID == "" || localUser.OIDCClientID == "" ||
|
||||
verified.Issuer != localUser.Issuer || verified.ApplicationID != localUser.ApplicationID ||
|
||||
verified.TenantID != localUser.TenantID || verified.OIDCClientID != localUser.OIDCClientID) {
|
||||
return "", ErrSessionInvalid
|
||||
}
|
||||
now := s.now()
|
||||
if !verified.TokenExpiresAt.After(now) {
|
||||
return "", ErrSessionExpired
|
||||
@@ -100,6 +106,8 @@ func (s *Service) Create(ctx context.Context, bundle TokenBundle, localUser *aut
|
||||
}
|
||||
_, err = s.repository.CreateOIDCSession(ctx, store.CreateOIDCSessionInput{
|
||||
SessionTokenHash: hash, GatewayUserID: localUser.GatewayUserID, GatewayTenantID: localUser.GatewayTenantID,
|
||||
OIDCUserBindingID: localUser.OIDCUserBindingID, OIDCClientID: verified.OIDCClientID,
|
||||
Issuer: verified.Issuer, ApplicationID: verified.ApplicationID, TenantID: verified.TenantID,
|
||||
TokenCiphertext: ciphertext, AccessTokenExpiresAt: verified.TokenExpiresAt,
|
||||
LastSeenAt: now, IdleExpiresAt: now.Add(s.config.IdleTTL), AbsoluteExpiresAt: now.Add(s.config.AbsoluteTTL),
|
||||
})
|
||||
@@ -142,6 +150,9 @@ func (s *Service) resolveRecord(ctx context.Context, hash []byte, record store.O
|
||||
}
|
||||
user, err := s.verifySessionUser(ctx, record, bundle.AccessToken)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrSessionInvalid) {
|
||||
_ = s.repository.DeleteOIDCSessionByID(ctx, record.ID)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if err := s.touch(ctx, record, now); err != nil {
|
||||
@@ -264,6 +275,11 @@ func (s *Service) verifySessionUser(ctx context.Context, record store.OIDCSessio
|
||||
if err != nil || user == nil || user.Source != "oidc" || user.ID != record.ExternalUserID {
|
||||
return nil, ErrSessionInvalid
|
||||
}
|
||||
if record.OIDCUserBindingID != "" &&
|
||||
(user.Issuer != record.Issuer || user.ApplicationID != record.ApplicationID ||
|
||||
user.TenantID != record.TenantID || user.OIDCClientID != record.OIDCClientID) {
|
||||
return nil, ErrSessionInvalid
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user