feat(api): add OAuth token fields and new provider types support

Add support for OAuth-based authentication with access/refresh tokens
and expiration tracking for API keys. Extend provider groups with
static headers configuration and headers profile options.

Changes include:
- Add AccessToken, RefreshToken, ExpiresAt, AccountID, ProjectID to APIKey model
- Add StaticHeaders and HeadersProfile to ProviderGroup model
- Add TokenRefresh configuration for background token management
- Support new provider types: ClaudeCode, Codex, GeminiCLI, Antigravity
- Update sync service to include new fields in provider snapshots
This commit is contained in:
zenfun
2025-12-28 02:49:54 +08:00
parent cca0802620
commit f0fe9f0dad
8 changed files with 132 additions and 22 deletions

View File

@@ -49,12 +49,20 @@ func (h *Handler) CreateAPIKey(c *gin.Context) {
}
key := model.APIKey{
GroupID: req.GroupID,
APIKey: apiKey,
Weight: normalizeWeight(req.Weight),
Status: status,
AutoBan: autoBan,
BanReason: strings.TrimSpace(req.BanReason),
GroupID: req.GroupID,
APIKey: apiKey,
AccessToken: strings.TrimSpace(req.AccessToken),
RefreshToken: strings.TrimSpace(req.RefreshToken),
AccountID: strings.TrimSpace(req.AccountID),
ProjectID: strings.TrimSpace(req.ProjectID),
Weight: normalizeWeight(req.Weight),
Status: status,
AutoBan: autoBan,
BanReason: strings.TrimSpace(req.BanReason),
}
if !req.ExpiresAt.IsZero() {
tu := req.ExpiresAt.UTC()
key.ExpiresAt = &tu
}
if !req.BanUntil.IsZero() {
tu := req.BanUntil.UTC()
@@ -180,6 +188,22 @@ func (h *Handler) UpdateAPIKey(c *gin.Context) {
if strings.TrimSpace(req.APIKey) != "" {
update["api_key"] = strings.TrimSpace(req.APIKey)
}
if strings.TrimSpace(req.AccessToken) != "" {
update["access_token"] = strings.TrimSpace(req.AccessToken)
}
if strings.TrimSpace(req.RefreshToken) != "" {
update["refresh_token"] = strings.TrimSpace(req.RefreshToken)
}
if !req.ExpiresAt.IsZero() {
tu := req.ExpiresAt.UTC()
update["expires_at"] = &tu
}
if strings.TrimSpace(req.AccountID) != "" {
update["account_id"] = strings.TrimSpace(req.AccountID)
}
if strings.TrimSpace(req.ProjectID) != "" {
update["project_id"] = strings.TrimSpace(req.ProjectID)
}
if req.Weight > 0 {
update["weight"] = normalizeWeight(req.Weight)
}
@@ -199,11 +223,17 @@ func (h *Handler) UpdateAPIKey(c *gin.Context) {
if req.BanUntil.IsZero() && strings.TrimSpace(req.Status) == "active" {
update["ban_until"] = nil
}
if req.GroupID != 0 || strings.TrimSpace(req.APIKey) != "" {
if req.GroupID != 0 || strings.TrimSpace(req.APIKey) != "" || strings.TrimSpace(req.AccessToken) != "" || strings.TrimSpace(req.RefreshToken) != "" {
nextKey := key
if v, ok := update["api_key"].(string); ok {
nextKey.APIKey = v
}
if v, ok := update["access_token"].(string); ok {
nextKey.AccessToken = v
}
if v, ok := update["refresh_token"].(string); ok {
nextKey.RefreshToken = v
}
if req.GroupID != 0 {
nextKey.GroupID = req.GroupID
}

View File

@@ -42,6 +42,8 @@ func (h *Handler) CreateProviderGroup(c *gin.Context) {
BaseURL: strings.TrimSpace(req.BaseURL),
GoogleProject: strings.TrimSpace(req.GoogleProject),
GoogleLocation: strings.TrimSpace(req.GoogleLocation),
StaticHeaders: strings.TrimSpace(req.StaticHeaders),
HeadersProfile: strings.TrimSpace(req.HeadersProfile),
Models: strings.Join(req.Models, ","),
Status: strings.TrimSpace(req.Status),
}
@@ -167,6 +169,12 @@ func (h *Handler) UpdateProviderGroup(c *gin.Context) {
if strings.TrimSpace(req.GoogleLocation) != "" {
next.GoogleLocation = strings.TrimSpace(req.GoogleLocation)
}
if strings.TrimSpace(req.StaticHeaders) != "" {
next.StaticHeaders = strings.TrimSpace(req.StaticHeaders)
}
if strings.TrimSpace(req.HeadersProfile) != "" {
next.HeadersProfile = strings.TrimSpace(req.HeadersProfile)
}
if req.Models != nil {
next.Models = strings.Join(req.Models, ",")
}
@@ -184,6 +192,8 @@ func (h *Handler) UpdateProviderGroup(c *gin.Context) {
group.BaseURL = normalized.BaseURL
group.GoogleProject = normalized.GoogleProject
group.GoogleLocation = normalized.GoogleLocation
group.StaticHeaders = normalized.StaticHeaders
group.HeadersProfile = normalized.HeadersProfile
group.Models = normalized.Models
group.Status = normalized.Status