- 后端: FastAPI + SQLAlchemy + SQLite, JWT认证, 代理支持的AirwallexClient - 前端: React 18 + Vite + Ant Design 5, 中文界面 - 功能: 卡片管理, 持卡人管理, 交易记录, API令牌, 系统设置, 审计日志 - 第三方API: X-API-Key认证, 权限控制 - Docker部署: docker-compose编排前后端
52 lines
1.8 KiB
Python
52 lines
1.8 KiB
Python
"""Airwallex client with proxy support."""
|
|
import httpx
|
|
from airwallex.client import AirwallexClient
|
|
|
|
|
|
class ProxiedAirwallexClient(AirwallexClient):
|
|
"""AirwallexClient that routes requests through an HTTP proxy."""
|
|
|
|
def __init__(self, proxy_url: str | None = None, **kwargs):
|
|
self._proxy_url = proxy_url
|
|
super().__init__(**kwargs)
|
|
# Replace the default httpx client with a proxied one
|
|
if proxy_url:
|
|
self._client.close()
|
|
self._client = httpx.Client(
|
|
base_url=self.base_url,
|
|
timeout=self.request_timeout,
|
|
proxy=proxy_url,
|
|
)
|
|
|
|
def authenticate(self) -> None:
|
|
"""Override authenticate to use proxy for auth requests too."""
|
|
from datetime import datetime, timezone
|
|
|
|
if self._token and self._token_expiry and datetime.now(timezone.utc) < self._token_expiry:
|
|
return
|
|
|
|
# Use a proxied client for authentication
|
|
auth_kwargs = {"timeout": self.request_timeout}
|
|
if self._proxy_url:
|
|
auth_kwargs["proxy"] = self._proxy_url
|
|
|
|
auth_client = httpx.Client(**auth_kwargs)
|
|
try:
|
|
response = auth_client.post(
|
|
self.auth_url,
|
|
headers={
|
|
"Content-Type": "application/json",
|
|
"x-client-id": self.client_id,
|
|
"x-api-key": self.api_key,
|
|
},
|
|
content="{}",
|
|
)
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
self._token = data.get("token")
|
|
# Token valid for 30 minutes, refresh a bit early
|
|
from datetime import timedelta
|
|
self._token_expiry = datetime.now(timezone.utc) + timedelta(minutes=28)
|
|
finally:
|
|
auth_client.close()
|