feat(core): 为OAuth模块添加代理支持

- 在_post_form函数中增加proxy_url参数,支持通过curl_cffi发送带代理的请求
- 更新OAuthManager构造函数,接收并传递代理配置
- 修改submit_callback_url函数签名,添加proxy_url参数
- 在RegistrationEngine中传递代理配置给OAuthManager
This commit is contained in:
cnlimiter
2026-03-15 02:06:11 +08:00
parent 845e712226
commit f3575c5795
2 changed files with 65 additions and 30 deletions

View File

@@ -8,12 +8,12 @@ import hashlib
import json import json
import secrets import secrets
import time import time
import urllib.error
import urllib.parse import urllib.parse
import urllib.request
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any, Dict, Optional from typing import Any, Dict, Optional
from curl_cffi import requests as cffi_requests
from ..config.constants import ( from ..config.constants import (
OAUTH_CLIENT_ID, OAUTH_CLIENT_ID,
OAUTH_AUTH_URL, OAUTH_AUTH_URL,
@@ -122,31 +122,59 @@ def _to_int(v: Any) -> int:
return 0 return 0
def _post_form(url: str, data: Dict[str, str], timeout: int = 30) -> Dict[str, Any]: def _post_form(
"""发送 POST 表单请求""" url: str,
body = urllib.parse.urlencode(data).encode("utf-8") data: Dict[str, str],
req = urllib.request.Request( timeout: int = 30,
url, proxy_url: Optional[str] = None
data=body, ) -> Dict[str, Any]:
method="POST", """
headers={ 发送 POST 表单请求
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json", Args:
}, url: 请求 URL
) data: 表单数据
timeout: 超时时间
proxy_url: 代理 URL
Returns:
响应 JSON 数据
"""
# 构建代理配置
proxies = None
if proxy_url:
proxies = {
"http": proxy_url,
"https": proxy_url,
}
headers = {
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
}
try: try:
with urllib.request.urlopen(req, timeout=timeout) as resp: # 使用 curl_cffi 发送请求,支持代理和浏览器指纹
raw = resp.read() response = cffi_requests.post(
if resp.status != 200: url,
raise RuntimeError( data=data,
f"token exchange failed: {resp.status}: {raw.decode('utf-8', 'replace')}" headers=headers,
) timeout=timeout,
return json.loads(raw.decode("utf-8")) proxies=proxies,
except urllib.error.HTTPError as exc: impersonate="chrome"
raw = exc.read() )
raise RuntimeError(
f"token exchange failed: {exc.code}: {raw.decode('utf-8', 'replace')}" if response.status_code != 200:
) from exc raise RuntimeError(
f"token exchange failed: {response.status_code}: {response.text}"
)
return response.json()
except cffi_requests.RequestsError as e:
raise RuntimeError(f"token exchange failed: network error: {e}") from e
@dataclass(frozen=True) @dataclass(frozen=True)
@@ -207,7 +235,8 @@ def submit_callback_url(
code_verifier: str, code_verifier: str,
redirect_uri: str = OAUTH_REDIRECT_URI, redirect_uri: str = OAUTH_REDIRECT_URI,
client_id: str = OAUTH_CLIENT_ID, client_id: str = OAUTH_CLIENT_ID,
token_url: str = OAUTH_TOKEN_URL token_url: str = OAUTH_TOKEN_URL,
proxy_url: Optional[str] = None
) -> str: ) -> str:
""" """
处理 OAuth 回调 URL获取访问令牌 处理 OAuth 回调 URL获取访问令牌
@@ -219,6 +248,7 @@ def submit_callback_url(
redirect_uri: 回调地址 redirect_uri: 回调地址
client_id: OpenAI Client ID client_id: OpenAI Client ID
token_url: Token 交换地址 token_url: Token 交换地址
proxy_url: 代理 URL
Returns: Returns:
包含访问令牌等信息的 JSON 字符串 包含访问令牌等信息的 JSON 字符串
@@ -248,6 +278,7 @@ def submit_callback_url(
"redirect_uri": redirect_uri, "redirect_uri": redirect_uri,
"code_verifier": code_verifier, "code_verifier": code_verifier,
}, },
proxy_url=proxy_url
) )
access_token = (token_resp.get("access_token") or "").strip() access_token = (token_resp.get("access_token") or "").strip()
@@ -289,13 +320,15 @@ class OAuthManager:
auth_url: str = OAUTH_AUTH_URL, auth_url: str = OAUTH_AUTH_URL,
token_url: str = OAUTH_TOKEN_URL, token_url: str = OAUTH_TOKEN_URL,
redirect_uri: str = OAUTH_REDIRECT_URI, redirect_uri: str = OAUTH_REDIRECT_URI,
scope: str = OAUTH_SCOPE scope: str = OAUTH_SCOPE,
proxy_url: Optional[str] = None
): ):
self.client_id = client_id self.client_id = client_id
self.auth_url = auth_url self.auth_url = auth_url
self.token_url = token_url self.token_url = token_url
self.redirect_uri = redirect_uri self.redirect_uri = redirect_uri
self.scope = scope self.scope = scope
self.proxy_url = proxy_url
def start_oauth(self) -> OAuthStart: def start_oauth(self) -> OAuthStart:
"""开始 OAuth 流程""" """开始 OAuth 流程"""
@@ -318,7 +351,8 @@ class OAuthManager:
code_verifier=code_verifier, code_verifier=code_verifier,
redirect_uri=self.redirect_uri, redirect_uri=self.redirect_uri,
client_id=self.client_id, client_id=self.client_id,
token_url=self.token_url token_url=self.token_url,
proxy_url=self.proxy_url
) )
return json.loads(result_json) return json.loads(result_json)

View File

@@ -106,7 +106,8 @@ class RegistrationEngine:
auth_url=settings.openai_auth_url, auth_url=settings.openai_auth_url,
token_url=settings.openai_token_url, token_url=settings.openai_token_url,
redirect_uri=settings.openai_redirect_uri, redirect_uri=settings.openai_redirect_uri,
scope=settings.openai_scope scope=settings.openai_scope,
proxy_url=proxy_url # 传递代理配置
) )
# 状态变量 # 状态变量