feat: 接入 OIDC 公共客户端登录链路

由 Gateway 服务端完成 PKCE 换码、ID Token 校验、JIT 用户解析和 Session 建立。新增登录、回调、退出与本地会话删除接口,并移除旧的 Access Token Cookie 桥接接口。
This commit is contained in:
2026-07-13 19:09:38 +08:00
parent d345c070ae
commit c5c82bb528
7 changed files with 658 additions and 281 deletions
@@ -32,22 +32,7 @@ func (s *Server) resolveGatewayUser(next http.Handler) http.Handler {
next.ServeHTTP(w, r)
return
}
if s.oidcUserResolver == nil {
s.writeOIDCUserResolutionError(w, r, errors.New("OIDC user resolver is unavailable"))
return
}
result, err := s.oidcUserResolver.ResolveOrProvisionOIDCUser(r.Context(), store.ResolveOrProvisionOIDCUserInput{
Issuer: s.cfg.OIDCIssuer,
Subject: user.ID,
Username: user.Username,
Roles: user.Roles,
TenantID: user.TenantID,
GatewayTenantKey: s.cfg.OIDCGatewayTenantKey,
ProvisioningEnabled: s.cfg.OIDCJITProvisioningEnabled,
RequestIP: limitAuditText(requestIP(r), 128),
UserAgent: limitAuditText(r.UserAgent(), 512),
})
result, err := s.resolveOIDCUserProjection(r.Context(), r, user)
if err != nil {
s.writeOIDCUserResolutionError(w, r, err)
return
@@ -66,6 +51,23 @@ func (s *Server) resolveGatewayUser(next http.Handler) http.Handler {
})
}
func (s *Server) resolveOIDCUserProjection(ctx context.Context, r *http.Request, user *auth.User) (store.ResolveOrProvisionOIDCUserResult, error) {
if s.oidcUserResolver == nil {
return store.ResolveOrProvisionOIDCUserResult{}, errors.New("OIDC user resolver is unavailable")
}
return s.oidcUserResolver.ResolveOrProvisionOIDCUser(ctx, store.ResolveOrProvisionOIDCUserInput{
Issuer: s.cfg.OIDCIssuer,
Subject: user.ID,
Username: user.Username,
Roles: user.Roles,
TenantID: user.TenantID,
GatewayTenantKey: s.cfg.OIDCGatewayTenantKey,
ProvisioningEnabled: s.cfg.OIDCJITProvisioningEnabled,
RequestIP: limitAuditText(requestIP(r), 128),
UserAgent: limitAuditText(r.UserAgent(), 512),
})
}
func (s *Server) writeOIDCUserResolutionError(w http.ResponseWriter, r *http.Request, err error) {
switch {
case errors.Is(err, store.ErrOIDCUserNotProvisioned):