refactor(access): migrate to SDKConfig for authentication and provider management

- Replaced `config.Config` with `SDKConfig` in authentication and provider logic for consistency with SDK changes.
- Updated provider registration, reconciliation, and build functions to align with the `SDKConfig` structure.
- Refactored related imports and handlers to support the new configuration approach.
- Improved clarity and reduced redundancy in API key synchronization and provider initialization.
This commit is contained in:
Luis Pater
2025-09-27 05:18:11 +08:00
parent 57c9ba49f4
commit d512f20c56
9 changed files with 124 additions and 119 deletions

View File

@@ -6,18 +6,20 @@ import (
"strings" "strings"
"github.com/router-for-me/CLIProxyAPI/v6/internal/config" "github.com/router-for-me/CLIProxyAPI/v6/internal/config"
"github.com/router-for-me/CLIProxyAPI/v6/sdk/access"
sdkConfig "github.com/router-for-me/CLIProxyAPI/v6/sdk/config"
) )
// ReconcileProviders builds the desired provider list by reusing existing providers when possible // ReconcileProviders builds the desired provider list by reusing existing providers when possible
// and creating or removing providers only when their configuration changed. It returns the final // and creating or removing providers only when their configuration changed. It returns the final
// ordered provider slice along with the identifiers of providers that were added, updated, or // ordered provider slice along with the identifiers of providers that were added, updated, or
// removed compared to the previous configuration. // removed compared to the previous configuration.
func ReconcileProviders(oldCfg, newCfg *config.Config, existing []Provider) (result []Provider, added, updated, removed []string, err error) { func ReconcileProviders(oldCfg, newCfg *config.Config, existing []access.Provider) (result []access.Provider, added, updated, removed []string, err error) {
if newCfg == nil { if newCfg == nil {
return nil, nil, nil, nil, nil return nil, nil, nil, nil, nil
} }
existingMap := make(map[string]Provider, len(existing)) existingMap := make(map[string]access.Provider, len(existing))
for _, provider := range existing { for _, provider := range existing {
if provider == nil { if provider == nil {
continue continue
@@ -28,11 +30,11 @@ func ReconcileProviders(oldCfg, newCfg *config.Config, existing []Provider) (res
oldCfgMap := accessProviderMap(oldCfg) oldCfgMap := accessProviderMap(oldCfg)
newEntries := collectProviderEntries(newCfg) newEntries := collectProviderEntries(newCfg)
result = make([]Provider, 0, len(newEntries)) result = make([]access.Provider, 0, len(newEntries))
finalIDs := make(map[string]struct{}, len(newEntries)) finalIDs := make(map[string]struct{}, len(newEntries))
isInlineProvider := func(id string) bool { isInlineProvider := func(id string) bool {
return strings.EqualFold(id, config.DefaultAccessProviderName) return strings.EqualFold(id, sdkConfig.DefaultAccessProviderName)
} }
appendChange := func(list *[]string, id string) { appendChange := func(list *[]string, id string) {
if isInlineProvider(id) { if isInlineProvider(id) {
@@ -58,7 +60,7 @@ func ReconcileProviders(oldCfg, newCfg *config.Config, existing []Provider) (res
} }
} }
provider, buildErr := buildProvider(providerCfg, newCfg) provider, buildErr := access.BuildProvider(providerCfg, &newCfg.SDKConfig)
if buildErr != nil { if buildErr != nil {
return nil, nil, nil, nil, buildErr return nil, nil, nil, nil, buildErr
} }
@@ -76,7 +78,7 @@ func ReconcileProviders(oldCfg, newCfg *config.Config, existing []Provider) (res
} }
if len(result) == 0 && len(newCfg.APIKeys) > 0 { if len(result) == 0 && len(newCfg.APIKeys) > 0 {
config.SyncInlineAPIKeys(newCfg, newCfg.APIKeys) sdkConfig.SyncInlineAPIKeys(&newCfg.SDKConfig, newCfg.APIKeys)
if providerCfg := newCfg.ConfigAPIKeyProvider(); providerCfg != nil { if providerCfg := newCfg.ConfigAPIKeyProvider(); providerCfg != nil {
key := providerIdentifier(providerCfg) key := providerIdentifier(providerCfg)
if key != "" { if key != "" {
@@ -86,7 +88,7 @@ func ReconcileProviders(oldCfg, newCfg *config.Config, existing []Provider) (res
if existingProvider, okExisting := existingMap[key]; okExisting { if existingProvider, okExisting := existingMap[key]; okExisting {
result = append(result, existingProvider) result = append(result, existingProvider)
} else { } else {
provider, buildErr := buildProvider(providerCfg, newCfg) provider, buildErr := access.BuildProvider(providerCfg, &newCfg.SDKConfig)
if buildErr != nil { if buildErr != nil {
return nil, nil, nil, nil, buildErr return nil, nil, nil, nil, buildErr
} }
@@ -98,7 +100,7 @@ func ReconcileProviders(oldCfg, newCfg *config.Config, existing []Provider) (res
result = append(result, provider) result = append(result, provider)
} }
} else { } else {
provider, buildErr := buildProvider(providerCfg, newCfg) provider, buildErr := access.BuildProvider(providerCfg, &newCfg.SDKConfig)
if buildErr != nil { if buildErr != nil {
return nil, nil, nil, nil, buildErr return nil, nil, nil, nil, buildErr
} }
@@ -110,7 +112,7 @@ func ReconcileProviders(oldCfg, newCfg *config.Config, existing []Provider) (res
result = append(result, provider) result = append(result, provider)
} }
} else { } else {
provider, buildErr := buildProvider(providerCfg, newCfg) provider, buildErr := access.BuildProvider(providerCfg, &newCfg.SDKConfig)
if buildErr != nil { if buildErr != nil {
return nil, nil, nil, nil, buildErr return nil, nil, nil, nil, buildErr
} }
@@ -144,8 +146,8 @@ func ReconcileProviders(oldCfg, newCfg *config.Config, existing []Provider) (res
return result, added, updated, removed, nil return result, added, updated, removed, nil
} }
func accessProviderMap(cfg *config.Config) map[string]*config.AccessProvider { func accessProviderMap(cfg *config.Config) map[string]*sdkConfig.AccessProvider {
result := make(map[string]*config.AccessProvider) result := make(map[string]*sdkConfig.AccessProvider)
if cfg == nil { if cfg == nil {
return result return result
} }
@@ -170,8 +172,8 @@ func accessProviderMap(cfg *config.Config) map[string]*config.AccessProvider {
return result return result
} }
func collectProviderEntries(cfg *config.Config) []*config.AccessProvider { func collectProviderEntries(cfg *config.Config) []*sdkConfig.AccessProvider {
entries := make([]*config.AccessProvider, 0, len(cfg.Access.Providers)) entries := make([]*sdkConfig.AccessProvider, 0, len(cfg.Access.Providers))
if cfg == nil { if cfg == nil {
return entries return entries
} }
@@ -187,7 +189,7 @@ func collectProviderEntries(cfg *config.Config) []*config.AccessProvider {
return entries return entries
} }
func providerIdentifier(provider *config.AccessProvider) string { func providerIdentifier(provider *sdkConfig.AccessProvider) string {
if provider == nil { if provider == nil {
return "" return ""
} }
@@ -198,13 +200,13 @@ func providerIdentifier(provider *config.AccessProvider) string {
if typ == "" { if typ == "" {
return "" return ""
} }
if strings.EqualFold(typ, config.AccessProviderTypeConfigAPIKey) { if strings.EqualFold(typ, sdkConfig.AccessProviderTypeConfigAPIKey) {
return config.DefaultAccessProviderName return sdkConfig.DefaultAccessProviderName
} }
return typ return typ
} }
func providerConfigEqual(a, b *config.AccessProvider) bool { func providerConfigEqual(a, b *sdkConfig.AccessProvider) bool {
if a == nil || b == nil { if a == nil || b == nil {
return a == nil && b == nil return a == nil && b == nil
} }

View File

@@ -6,6 +6,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/router-for-me/CLIProxyAPI/v6/internal/config" "github.com/router-for-me/CLIProxyAPI/v6/internal/config"
sdkConfig "github.com/router-for-me/CLIProxyAPI/v6/sdk/config"
) )
// Generic helpers for list[string] // Generic helpers for list[string]
@@ -106,13 +107,13 @@ func (h *Handler) deleteFromStringList(c *gin.Context, target *[]string, after f
// api-keys // api-keys
func (h *Handler) GetAPIKeys(c *gin.Context) { c.JSON(200, gin.H{"api-keys": h.cfg.APIKeys}) } func (h *Handler) GetAPIKeys(c *gin.Context) { c.JSON(200, gin.H{"api-keys": h.cfg.APIKeys}) }
func (h *Handler) PutAPIKeys(c *gin.Context) { func (h *Handler) PutAPIKeys(c *gin.Context) {
h.putStringList(c, func(v []string) { config.SyncInlineAPIKeys(h.cfg, v) }, nil) h.putStringList(c, func(v []string) { sdkConfig.SyncInlineAPIKeys(&h.cfg.SDKConfig, v) }, nil)
} }
func (h *Handler) PatchAPIKeys(c *gin.Context) { func (h *Handler) PatchAPIKeys(c *gin.Context) {
h.patchStringList(c, &h.cfg.APIKeys, func() { config.SyncInlineAPIKeys(h.cfg, h.cfg.APIKeys) }) h.patchStringList(c, &h.cfg.APIKeys, func() { sdkConfig.SyncInlineAPIKeys(&h.cfg.SDKConfig, h.cfg.APIKeys) })
} }
func (h *Handler) DeleteAPIKeys(c *gin.Context) { func (h *Handler) DeleteAPIKeys(c *gin.Context) {
h.deleteFromStringList(c, &h.cfg.APIKeys, func() { config.SyncInlineAPIKeys(h.cfg, h.cfg.APIKeys) }) h.deleteFromStringList(c, &h.cfg.APIKeys, func() { sdkConfig.SyncInlineAPIKeys(&h.cfg.SDKConfig, h.cfg.APIKeys) })
} }
// generative-language-api-key // generative-language-api-key

View File

@@ -16,6 +16,7 @@ import (
"time" "time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/router-for-me/CLIProxyAPI/v6/internal/access"
managementHandlers "github.com/router-for-me/CLIProxyAPI/v6/internal/api/handlers/management" managementHandlers "github.com/router-for-me/CLIProxyAPI/v6/internal/api/handlers/management"
"github.com/router-for-me/CLIProxyAPI/v6/internal/api/middleware" "github.com/router-for-me/CLIProxyAPI/v6/internal/api/middleware"
"github.com/router-for-me/CLIProxyAPI/v6/internal/config" "github.com/router-for-me/CLIProxyAPI/v6/internal/config"
@@ -25,8 +26,8 @@ import (
sdkaccess "github.com/router-for-me/CLIProxyAPI/v6/sdk/access" sdkaccess "github.com/router-for-me/CLIProxyAPI/v6/sdk/access"
"github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers" "github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers"
"github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers/claude" "github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers/claude"
gemini2 "github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers/gemini" "github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers/gemini"
openai2 "github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers/openai" "github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers/openai"
"github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth" "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@@ -224,11 +225,11 @@ func NewServer(cfg *config.Config, authManager *auth.Manager, accessManager *sdk
// setupRoutes configures the API routes for the server. // setupRoutes configures the API routes for the server.
// It defines the endpoints and associates them with their respective handlers. // It defines the endpoints and associates them with their respective handlers.
func (s *Server) setupRoutes() { func (s *Server) setupRoutes() {
openaiHandlers := openai2.NewOpenAIAPIHandler(s.handlers) openaiHandlers := openai.NewOpenAIAPIHandler(s.handlers)
geminiHandlers := gemini2.NewGeminiAPIHandler(s.handlers) geminiHandlers := gemini.NewGeminiAPIHandler(s.handlers)
geminiCLIHandlers := gemini2.NewGeminiCLIAPIHandler(s.handlers) geminiCLIHandlers := gemini.NewGeminiCLIAPIHandler(s.handlers)
claudeCodeHandlers := claude.NewClaudeCodeAPIHandler(s.handlers) claudeCodeHandlers := claude.NewClaudeCodeAPIHandler(s.handlers)
openaiResponsesHandlers := openai2.NewOpenAIResponsesAPIHandler(s.handlers) openaiResponsesHandlers := openai.NewOpenAIResponsesAPIHandler(s.handlers)
// OpenAI compatible API routes // OpenAI compatible API routes
v1 := s.engine.Group("/v1") v1 := s.engine.Group("/v1")
@@ -469,7 +470,7 @@ func (s *Server) watchKeepAlive() {
// that routes to different handlers based on the User-Agent header. // that routes to different handlers based on the User-Agent header.
// If User-Agent starts with "claude-cli", it routes to Claude handler, // If User-Agent starts with "claude-cli", it routes to Claude handler,
// otherwise it routes to OpenAI handler. // otherwise it routes to OpenAI handler.
func (s *Server) unifiedModelsHandler(openaiHandler *openai2.OpenAIAPIHandler, claudeHandler *claude.ClaudeCodeAPIHandler) gin.HandlerFunc { func (s *Server) unifiedModelsHandler(openaiHandler *openai.OpenAIAPIHandler, claudeHandler *claude.ClaudeCodeAPIHandler) gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
userAgent := c.GetHeader("User-Agent") userAgent := c.GetHeader("User-Agent")
@@ -552,7 +553,7 @@ func (s *Server) applyAccessConfig(oldCfg, newCfg *config.Config) {
return return
} }
existing := s.accessManager.Providers() existing := s.accessManager.Providers()
providers, added, updated, removed, err := sdkaccess.ReconcileProviders(oldCfg, newCfg, existing) providers, added, updated, removed, err := access.ReconcileProviders(oldCfg, newCfg, existing)
if err != nil { if err != nil {
log.Errorf("failed to reconcile request auth providers: %v", err) log.Errorf("failed to reconcile request auth providers: %v", err)
return return

View File

@@ -31,12 +31,6 @@ type Config struct {
// UsageStatisticsEnabled toggles in-memory usage aggregation; when false, usage data is discarded. // UsageStatisticsEnabled toggles in-memory usage aggregation; when false, usage data is discarded.
UsageStatisticsEnabled bool `yaml:"usage-statistics-enabled" json:"usage-statistics-enabled"` UsageStatisticsEnabled bool `yaml:"usage-statistics-enabled" json:"usage-statistics-enabled"`
// APIKeys is a list of keys for authenticating clients to this proxy server.
APIKeys []string `yaml:"api-keys" json:"api-keys"`
// Access holds request authentication provider configuration.
Access AccessConfig `yaml:"auth" json:"auth"`
// QuotaExceeded defines the behavior when a quota is exceeded. // QuotaExceeded defines the behavior when a quota is exceeded.
QuotaExceeded QuotaExceeded `yaml:"quota-exceeded" json:"quota-exceeded"` QuotaExceeded QuotaExceeded `yaml:"quota-exceeded" json:"quota-exceeded"`
@@ -62,38 +56,6 @@ type Config struct {
GeminiWeb GeminiWebConfig `yaml:"gemini-web" json:"gemini-web"` GeminiWeb GeminiWebConfig `yaml:"gemini-web" json:"gemini-web"`
} }
// AccessConfig groups request authentication providers.
type AccessConfig struct {
// Providers lists configured authentication providers.
Providers []AccessProvider `yaml:"providers" json:"providers"`
}
// AccessProvider describes a request authentication provider entry.
type AccessProvider struct {
// Name is the instance identifier for the provider.
Name string `yaml:"name" json:"name"`
// Type selects the provider implementation registered via the SDK.
Type string `yaml:"type" json:"type"`
// SDK optionally names a third-party SDK module providing this provider.
SDK string `yaml:"sdk,omitempty" json:"sdk,omitempty"`
// APIKeys lists inline keys for providers that require them.
APIKeys []string `yaml:"api-keys,omitempty" json:"api-keys,omitempty"`
// Config passes provider-specific options to the implementation.
Config map[string]any `yaml:"config,omitempty" json:"config,omitempty"`
}
const (
// AccessProviderTypeConfigAPIKey is the built-in provider validating inline API keys.
AccessProviderTypeConfigAPIKey = "config-api-key"
// DefaultAccessProviderName is applied when no provider name is supplied.
DefaultAccessProviderName = "config-inline"
)
// GeminiWebConfig nests Gemini Web related options under 'gemini-web'. // GeminiWebConfig nests Gemini Web related options under 'gemini-web'.
type GeminiWebConfig struct { type GeminiWebConfig struct {
// Context enables JSON-based conversation reuse. // Context enables JSON-based conversation reuse.
@@ -232,43 +194,6 @@ func LoadConfig(configFile string) (*Config, error) {
return &cfg, nil return &cfg, nil
} }
// SyncInlineAPIKeys updates the inline API key provider and top-level APIKeys field.
func SyncInlineAPIKeys(cfg *Config, keys []string) {
if cfg == nil {
return
}
cloned := append([]string(nil), keys...)
cfg.APIKeys = cloned
if provider := cfg.ConfigAPIKeyProvider(); provider != nil {
if provider.Name == "" {
provider.Name = DefaultAccessProviderName
}
provider.APIKeys = cloned
return
}
cfg.Access.Providers = append(cfg.Access.Providers, AccessProvider{
Name: DefaultAccessProviderName,
Type: AccessProviderTypeConfigAPIKey,
APIKeys: cloned,
})
}
// ConfigAPIKeyProvider returns the first inline API key provider if present.
func (c *Config) ConfigAPIKeyProvider() *AccessProvider {
if c == nil {
return nil
}
for i := range c.Access.Providers {
if c.Access.Providers[i].Type == AccessProviderTypeConfigAPIKey {
if c.Access.Providers[i].Name == "" {
c.Access.Providers[i].Name = DefaultAccessProviderName
}
return &c.Access.Providers[i]
}
}
return nil
}
func syncInlineAccessProvider(cfg *Config) { func syncInlineAccessProvider(cfg *Config) {
if cfg == nil { if cfg == nil {
return return
@@ -277,9 +202,9 @@ func syncInlineAccessProvider(cfg *Config) {
if len(cfg.APIKeys) == 0 { if len(cfg.APIKeys) == 0 {
return return
} }
cfg.Access.Providers = append(cfg.Access.Providers, AccessProvider{ cfg.Access.Providers = append(cfg.Access.Providers, config.AccessProvider{
Name: DefaultAccessProviderName, Name: config.DefaultAccessProviderName,
Type: AccessProviderTypeConfigAPIKey, Type: config.AccessProviderTypeConfigAPIKey,
APIKeys: append([]string(nil), cfg.APIKeys...), APIKeys: append([]string(nil), cfg.APIKeys...),
}) })
return return
@@ -289,9 +214,9 @@ func syncInlineAccessProvider(cfg *Config) {
if len(cfg.APIKeys) == 0 { if len(cfg.APIKeys) == 0 {
return return
} }
cfg.Access.Providers = append(cfg.Access.Providers, AccessProvider{ cfg.Access.Providers = append(cfg.Access.Providers, config.AccessProvider{
Name: DefaultAccessProviderName, Name: config.DefaultAccessProviderName,
Type: AccessProviderTypeConfigAPIKey, Type: config.AccessProviderTypeConfigAPIKey,
APIKeys: append([]string(nil), cfg.APIKeys...), APIKeys: append([]string(nil), cfg.APIKeys...),
}) })
return return

View File

@@ -5,8 +5,8 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
sdkaccess "github.com/router-for-me/CLIProxyAPI/v6/sdk/access" sdkaccess "github.com/router-for-me/CLIProxyAPI/v6/sdk/access"
"github.com/router-for-me/CLIProxyAPI/v6/sdk/config"
) )
type provider struct { type provider struct {
@@ -18,7 +18,7 @@ func init() {
sdkaccess.RegisterProvider(config.AccessProviderTypeConfigAPIKey, newProvider) sdkaccess.RegisterProvider(config.AccessProviderTypeConfigAPIKey, newProvider)
} }
func newProvider(cfg *config.AccessProvider, _ *config.Config) (sdkaccess.Provider, error) { func newProvider(cfg *config.AccessProvider, _ *config.SDKConfig) (sdkaccess.Provider, error) {
name := cfg.Name name := cfg.Name
if name == "" { if name == "" {
name = config.DefaultAccessProviderName name = config.DefaultAccessProviderName

View File

@@ -6,7 +6,7 @@ import (
"net/http" "net/http"
"sync" "sync"
"github.com/router-for-me/CLIProxyAPI/v6/internal/config" "github.com/router-for-me/CLIProxyAPI/v6/sdk/config"
) )
// Provider validates credentials for incoming requests. // Provider validates credentials for incoming requests.
@@ -23,7 +23,7 @@ type Result struct {
} }
// ProviderFactory builds a provider from configuration data. // ProviderFactory builds a provider from configuration data.
type ProviderFactory func(cfg *config.AccessProvider, root *config.Config) (Provider, error) type ProviderFactory func(cfg *config.AccessProvider, root *config.SDKConfig) (Provider, error)
var ( var (
registryMu sync.RWMutex registryMu sync.RWMutex
@@ -40,7 +40,7 @@ func RegisterProvider(typ string, factory ProviderFactory) {
registryMu.Unlock() registryMu.Unlock()
} }
func buildProvider(cfg *config.AccessProvider, root *config.Config) (Provider, error) { func BuildProvider(cfg *config.AccessProvider, root *config.SDKConfig) (Provider, error) {
if cfg == nil { if cfg == nil {
return nil, fmt.Errorf("access: nil provider config") return nil, fmt.Errorf("access: nil provider config")
} }
@@ -58,7 +58,7 @@ func buildProvider(cfg *config.AccessProvider, root *config.Config) (Provider, e
} }
// BuildProviders constructs providers declared in configuration. // BuildProviders constructs providers declared in configuration.
func BuildProviders(root *config.Config) ([]Provider, error) { func BuildProviders(root *config.SDKConfig) ([]Provider, error) {
if root == nil { if root == nil {
return nil, nil return nil, nil
} }
@@ -68,7 +68,7 @@ func BuildProviders(root *config.Config) ([]Provider, error) {
if providerCfg.Type == "" { if providerCfg.Type == "" {
continue continue
} }
provider, err := buildProvider(providerCfg, root) provider, err := BuildProvider(providerCfg, root)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -77,7 +77,7 @@ func BuildProviders(root *config.Config) ([]Provider, error) {
if len(providers) == 0 && len(root.APIKeys) > 0 { if len(providers) == 0 && len(root.APIKeys) > 0 {
config.SyncInlineAPIKeys(root, root.APIKeys) config.SyncInlineAPIKeys(root, root.APIKeys)
if providerCfg := root.ConfigAPIKeyProvider(); providerCfg != nil { if providerCfg := root.ConfigAPIKeyProvider(); providerCfg != nil {
provider, err := buildProvider(providerCfg, root) provider, err := BuildProvider(providerCfg, root)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -184,7 +184,7 @@ func (b *Builder) Build() (*Service, error) {
if accessManager == nil { if accessManager == nil {
accessManager = sdkaccess.NewManager() accessManager = sdkaccess.NewManager()
} }
providers, err := sdkaccess.BuildProviders(b.cfg) providers, err := sdkaccess.BuildProviders(&b.cfg.SDKConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -12,6 +12,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/router-for-me/CLIProxyAPI/v6/internal/access"
"github.com/router-for-me/CLIProxyAPI/v6/internal/api" "github.com/router-for-me/CLIProxyAPI/v6/internal/api"
"github.com/router-for-me/CLIProxyAPI/v6/internal/config" "github.com/router-for-me/CLIProxyAPI/v6/internal/config"
geminiwebclient "github.com/router-for-me/CLIProxyAPI/v6/internal/provider/gemini-web" geminiwebclient "github.com/router-for-me/CLIProxyAPI/v6/internal/provider/gemini-web"
@@ -115,7 +116,7 @@ func (s *Service) refreshAccessProviders(cfg *config.Config) {
s.cfgMu.RUnlock() s.cfgMu.RUnlock()
existing := s.accessManager.Providers() existing := s.accessManager.Providers()
providers, added, updated, removed, err := sdkaccess.ReconcileProviders(oldCfg, cfg, existing) providers, added, updated, removed, err := access.ReconcileProviders(oldCfg, cfg, existing)
if err != nil { if err != nil {
log.Errorf("failed to reconcile request auth providers: %v", err) log.Errorf("failed to reconcile request auth providers: %v", err)
return return

View File

@@ -11,4 +11,79 @@ type SDKConfig struct {
// RequestLog enables or disables detailed request logging functionality. // RequestLog enables or disables detailed request logging functionality.
RequestLog bool `yaml:"request-log" json:"request-log"` RequestLog bool `yaml:"request-log" json:"request-log"`
// APIKeys is a list of keys for authenticating clients to this proxy server.
APIKeys []string `yaml:"api-keys" json:"api-keys"`
// Access holds request authentication provider configuration.
Access AccessConfig `yaml:"auth" json:"auth"`
}
// AccessConfig groups request authentication providers.
type AccessConfig struct {
// Providers lists configured authentication providers.
Providers []AccessProvider `yaml:"providers" json:"providers"`
}
// AccessProvider describes a request authentication provider entry.
type AccessProvider struct {
// Name is the instance identifier for the provider.
Name string `yaml:"name" json:"name"`
// Type selects the provider implementation registered via the SDK.
Type string `yaml:"type" json:"type"`
// SDK optionally names a third-party SDK module providing this provider.
SDK string `yaml:"sdk,omitempty" json:"sdk,omitempty"`
// APIKeys lists inline keys for providers that require them.
APIKeys []string `yaml:"api-keys,omitempty" json:"api-keys,omitempty"`
// Config passes provider-specific options to the implementation.
Config map[string]any `yaml:"config,omitempty" json:"config,omitempty"`
}
const (
// AccessProviderTypeConfigAPIKey is the built-in provider validating inline API keys.
AccessProviderTypeConfigAPIKey = "config-api-key"
// DefaultAccessProviderName is applied when no provider name is supplied.
DefaultAccessProviderName = "config-inline"
)
// SyncInlineAPIKeys updates the inline API key provider and top-level APIKeys field.
func SyncInlineAPIKeys(cfg *SDKConfig, keys []string) {
if cfg == nil {
return
}
cloned := append([]string(nil), keys...)
cfg.APIKeys = cloned
if provider := cfg.ConfigAPIKeyProvider(); provider != nil {
if provider.Name == "" {
provider.Name = DefaultAccessProviderName
}
provider.APIKeys = cloned
return
}
cfg.Access.Providers = append(cfg.Access.Providers, AccessProvider{
Name: DefaultAccessProviderName,
Type: AccessProviderTypeConfigAPIKey,
APIKeys: cloned,
})
}
// ConfigAPIKeyProvider returns the first inline API key provider if present.
func (c *SDKConfig) ConfigAPIKeyProvider() *AccessProvider {
if c == nil {
return nil
}
for i := range c.Access.Providers {
if c.Access.Providers[i].Type == AccessProviderTypeConfigAPIKey {
if c.Access.Providers[i].Name == "" {
c.Access.Providers[i].Name = DefaultAccessProviderName
}
return &c.Access.Providers[i]
}
}
return nil
} }