feat(identity): 实现统一认证运行时热切换
从 Active Revision 构造并验证 OIDC、BFF Session、Introspection 与 SSF Runtime,在数据库激活成功后原子替换内存引用。请求链路使用不可变快照,失败保留当前运行时,本地管理登录不受影响。\n\n验证:go test ./apps/api/...;go vet ./apps/api/...
This commit is contained in:
@@ -73,16 +73,19 @@ func NewRequestAuthError(status int, code, message string) error {
|
||||
}
|
||||
|
||||
type Authenticator struct {
|
||||
JWTSecret string
|
||||
ServerMainBaseURL string
|
||||
ServerMainInternalToken string
|
||||
ServerMainInternalKey string
|
||||
ServerMainInternalSecret string
|
||||
HTTPClient *http.Client
|
||||
LocalAPIKeyVerifier func(ctx context.Context, apiKey string) (*User, error)
|
||||
OIDCVerifier *OIDCVerifier
|
||||
OIDCSessionResolver func(ctx context.Context, sessionID string) (*User, error)
|
||||
LegacyJWTEnabled bool
|
||||
JWTSecret string
|
||||
ServerMainBaseURL string
|
||||
ServerMainInternalToken string
|
||||
ServerMainInternalKey string
|
||||
ServerMainInternalSecret string
|
||||
HTTPClient *http.Client
|
||||
LocalAPIKeyVerifier func(ctx context.Context, apiKey string) (*User, error)
|
||||
OIDCVerifier *OIDCVerifier
|
||||
OIDCVerifierProvider func() *OIDCVerifier
|
||||
OIDCSessionResolver func(ctx context.Context, sessionID string) (*User, error)
|
||||
OIDCSessionResolverProvider func(ctx context.Context, sessionID string) (*User, error)
|
||||
LegacyJWTEnabled bool
|
||||
LegacyJWTEnabledProvider func() bool
|
||||
}
|
||||
|
||||
func New(jwtSecret string, serverMainBaseURL string, internalToken string) *Authenticator {
|
||||
@@ -152,10 +155,14 @@ func (a *Authenticator) Authenticate(r *http.Request) (*User, error) {
|
||||
if token == "" {
|
||||
if cookie, err := r.Cookie(OIDCSessionCookieName); err == nil {
|
||||
sessionID := strings.TrimSpace(cookie.Value)
|
||||
if sessionID == "" || a.OIDCSessionResolver == nil {
|
||||
resolver := a.OIDCSessionResolver
|
||||
if a.OIDCSessionResolverProvider != nil {
|
||||
resolver = a.OIDCSessionResolverProvider
|
||||
}
|
||||
if sessionID == "" || resolver == nil {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
return a.OIDCSessionResolver(r.Context(), sessionID)
|
||||
return resolver(r.Context(), sessionID)
|
||||
}
|
||||
}
|
||||
if token == "" {
|
||||
@@ -168,7 +175,7 @@ func (a *Authenticator) Authenticate(r *http.Request) (*User, error) {
|
||||
if algorithm == "RS256" || algorithm == "ES256" {
|
||||
return a.AuthenticateOIDCAccessToken(r.Context(), token)
|
||||
}
|
||||
if !a.LegacyJWTEnabled {
|
||||
if !a.legacyJWTEnabled() {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
return a.verifyJWT(token)
|
||||
@@ -176,10 +183,21 @@ func (a *Authenticator) Authenticate(r *http.Request) (*User, error) {
|
||||
|
||||
func (a *Authenticator) AuthenticateOIDCAccessToken(ctx context.Context, token string) (*User, error) {
|
||||
algorithm := jwtAlgorithm(token)
|
||||
if a.OIDCVerifier == nil || algorithm != "RS256" && algorithm != "ES256" {
|
||||
verifier := a.OIDCVerifier
|
||||
if a.OIDCVerifierProvider != nil {
|
||||
verifier = a.OIDCVerifierProvider()
|
||||
}
|
||||
if verifier == nil || algorithm != "RS256" && algorithm != "ES256" {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
return a.OIDCVerifier.Verify(ctx, token)
|
||||
return verifier.Verify(ctx, token)
|
||||
}
|
||||
|
||||
func (a *Authenticator) legacyJWTEnabled() bool {
|
||||
if a.LegacyJWTEnabledProvider != nil {
|
||||
return a.LegacyJWTEnabledProvider()
|
||||
}
|
||||
return a.LegacyJWTEnabled
|
||||
}
|
||||
|
||||
func (a *Authenticator) verifyJWT(tokenString string) (*User, error) {
|
||||
|
||||
Reference in New Issue
Block a user