mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 09:20:22 +08:00
feat: 支持固定类型 Provider OAuth 授权
- 新增 provider_type 字段区分自定义/预置 Provider 类型(claude_code/codex/gemini_cli/antigravity) - 实现完整 OAuth 2.0 授权流程:start(生成授权 URL + PKCE)、complete(换取 token)、refresh - 前端 KeyFormDialog 添加 OAuth 授权 UI,支持开始授权、粘贴回调 URL、完成授权、强制刷新 - 请求时自动检测 token 过期并刷新(120s 预留窗口 + Redis 分布式锁防并发) - 固定类型 Provider 自动创建预置端点并锁定 base_url/custom_path - 数据库迁移:添加 providers.provider_type,扩展 api_key 列为 TEXT - 可选依赖 tls-client 用于 Claude token 请求的 TLS 指纹伪装
This commit is contained in:
@@ -2,6 +2,7 @@ export * from './types'
|
||||
export * from './providers'
|
||||
export * from './endpoints'
|
||||
export * from './keys'
|
||||
export * from './provider_oauth'
|
||||
export * from './health'
|
||||
export * from './models'
|
||||
export * from './adaptive'
|
||||
|
||||
@@ -56,7 +56,7 @@ export async function getModelCapabilities(modelName: string): Promise<ModelCapa
|
||||
* 获取完整的 API Key(用于查看和复制)
|
||||
*/
|
||||
export interface RevealKeyResult {
|
||||
auth_type: 'api_key' | 'vertex_ai'
|
||||
auth_type: 'api_key' | 'vertex_ai' | 'oauth'
|
||||
api_key?: string
|
||||
auth_config?: string | Record<string, any>
|
||||
}
|
||||
@@ -94,7 +94,7 @@ export async function addProviderKey(
|
||||
data: {
|
||||
api_formats: string[] // 支持的 API 格式列表(必填)
|
||||
api_key: string
|
||||
auth_type?: 'api_key' | 'vertex_ai' // 认证类型
|
||||
auth_type?: 'api_key' | 'vertex_ai' | 'oauth' // 认证类型
|
||||
auth_config?: Record<string, any> // 认证配置(Vertex AI Service Account JSON)
|
||||
name: string
|
||||
rate_multipliers?: Record<string, number> | null // 按 API 格式的成本倍率
|
||||
@@ -122,7 +122,7 @@ export async function updateProviderKey(
|
||||
data: Partial<{
|
||||
api_formats: string[] // 支持的 API 格式列表
|
||||
api_key: string
|
||||
auth_type: 'api_key' | 'vertex_ai' // 认证类型
|
||||
auth_type: 'api_key' | 'vertex_ai' | 'oauth' // 认证类型
|
||||
auth_config: Record<string, any> // 认证配置(Vertex AI Service Account JSON)
|
||||
name: string
|
||||
rate_multipliers: Record<string, number> | null // 按 API 格式的成本倍率
|
||||
|
||||
51
frontend/src/api/endpoints/provider_oauth.ts
Normal file
51
frontend/src/api/endpoints/provider_oauth.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import client from '../client'
|
||||
|
||||
export interface ProviderOAuthSupportedType {
|
||||
provider_type: string
|
||||
display_name: string
|
||||
scopes: string[]
|
||||
redirect_uri: string
|
||||
authorize_url: string
|
||||
token_url: string
|
||||
use_pkce: boolean
|
||||
}
|
||||
|
||||
export interface ProviderOAuthStartResponse {
|
||||
authorization_url: string
|
||||
redirect_uri: string
|
||||
provider_type: string
|
||||
instructions: string
|
||||
}
|
||||
|
||||
export interface ProviderOAuthCompleteRequest {
|
||||
callback_url: string
|
||||
}
|
||||
|
||||
export interface ProviderOAuthCompleteResponse {
|
||||
provider_type: string
|
||||
expires_at?: number | null
|
||||
has_refresh_token: boolean
|
||||
}
|
||||
|
||||
export async function getProviderOAuthSupportedTypes(): Promise<ProviderOAuthSupportedType[]> {
|
||||
const resp = await client.get('/api/admin/provider-oauth/supported-types')
|
||||
return resp.data
|
||||
}
|
||||
|
||||
export async function startProviderOAuth(keyId: string): Promise<ProviderOAuthStartResponse> {
|
||||
const resp = await client.post(`/api/admin/provider-oauth/keys/${keyId}/start`)
|
||||
return resp.data
|
||||
}
|
||||
|
||||
export async function completeProviderOAuth(
|
||||
keyId: string,
|
||||
data: ProviderOAuthCompleteRequest
|
||||
): Promise<ProviderOAuthCompleteResponse> {
|
||||
const resp = await client.post(`/api/admin/provider-oauth/keys/${keyId}/complete`, data)
|
||||
return resp.data
|
||||
}
|
||||
|
||||
export async function refreshProviderOAuth(keyId: string): Promise<ProviderOAuthCompleteResponse> {
|
||||
const resp = await client.post(`/api/admin/provider-oauth/keys/${keyId}/refresh`)
|
||||
return resp.data
|
||||
}
|
||||
@@ -24,6 +24,7 @@ export async function updateProvider(
|
||||
providerId: string,
|
||||
data: Partial<{
|
||||
name: string
|
||||
provider_type: 'custom' | 'claude_code' | 'codex' | 'gemini_cli' | 'antigravity'
|
||||
description: string
|
||||
website: string
|
||||
provider_priority: number
|
||||
@@ -38,6 +39,7 @@ export async function updateProvider(
|
||||
proxy: ProxyConfig | null
|
||||
cache_ttl_minutes: number // 0表示不支持缓存,>0表示支持缓存并设置TTL(分钟)
|
||||
max_probe_interval_minutes: number
|
||||
enable_format_conversion: boolean // 是否允许格式转换(提供商级别开关)
|
||||
is_active: boolean
|
||||
}>
|
||||
): Promise<ProviderWithEndpointsSummary> {
|
||||
@@ -48,7 +50,26 @@ export async function updateProvider(
|
||||
/**
|
||||
* 创建 Provider
|
||||
*/
|
||||
export async function createProvider(data: any): Promise<any> {
|
||||
export async function createProvider(
|
||||
data: {
|
||||
name: string
|
||||
provider_type?: 'custom' | 'claude_code' | 'codex' | 'gemini_cli' | 'antigravity'
|
||||
description?: string
|
||||
website?: string
|
||||
billing_type?: 'monthly_quota' | 'pay_as_you_go' | 'free_tier'
|
||||
monthly_quota_usd?: number
|
||||
quota_reset_day?: number
|
||||
quota_last_reset_at?: string
|
||||
quota_expires_at?: string
|
||||
provider_priority?: number
|
||||
keep_priority_on_conversion?: boolean
|
||||
is_active?: boolean
|
||||
max_retries?: number
|
||||
stream_first_byte_timeout?: number | null
|
||||
request_timeout?: number | null
|
||||
proxy?: ProxyConfig | null
|
||||
}
|
||||
): Promise<{ id: string; name: string; message?: string }> {
|
||||
const response = await client.post('/api/admin/providers/', data)
|
||||
return response.data
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ export interface EndpointAPIKey {
|
||||
api_formats: string[] // 支持的 endpoint signature 列表(如 "openai:chat")
|
||||
api_key_masked: string
|
||||
api_key_plain?: string | null
|
||||
auth_type: 'api_key' | 'vertex_ai' // 认证类型(必返回)
|
||||
auth_type: 'api_key' | 'vertex_ai' | 'oauth' // 认证类型(必返回)
|
||||
name: string // 密钥名称(必填,用于识别)
|
||||
rate_multipliers?: Record<string, number> | null // 按 endpoint signature 的成本倍率
|
||||
internal_priority: number // Key 内部优先级
|
||||
@@ -273,7 +273,7 @@ export interface EndpointAPIKeyUpdate {
|
||||
api_formats?: string[] // 支持的 API 格式列表
|
||||
name?: string
|
||||
api_key?: string // 仅在需要更新时提供
|
||||
auth_type?: 'api_key' | 'vertex_ai' // 认证类型
|
||||
auth_type?: 'api_key' | 'vertex_ai' | 'oauth' // 认证类型
|
||||
auth_config?: Record<string, any> // 认证配置(Vertex AI Service Account JSON)
|
||||
rate_multipliers?: Record<string, number> | null // 按 API 格式的成本倍率
|
||||
internal_priority?: number
|
||||
@@ -360,9 +360,12 @@ export interface PublicEndpointStatusMonitorResponse {
|
||||
formats: PublicEndpointStatusMonitor[]
|
||||
}
|
||||
|
||||
export type ProviderType = 'custom' | 'claude_code' | 'codex' | 'gemini_cli' | 'antigravity'
|
||||
|
||||
export interface ProviderWithEndpointsSummary {
|
||||
id: string
|
||||
name: string
|
||||
provider_type?: ProviderType
|
||||
description?: string
|
||||
website?: string
|
||||
provider_priority: number
|
||||
|
||||
Reference in New Issue
Block a user