refactor: 移除 Python 后端源码,全面迁移至 Rust gateway 架构

- 删除全部 Python 源码 (src/) 及 Alembic 迁移脚本,归档至 _deprecated_py_src/
- 重构 Rust gateway ai_pipeline: 拆分 planner/finalize 模块,新增 contracts/adaptation 层
- 重组 handlers 模块为 admin/public/proxy/internal/shared 子模块结构
- 新增 executor 模块,引入 Rust 原生数据库迁移 (aether-data/migrations)
- 简化 CI/Docker 构建流程,移除 base image 二级构建,统一为单一 app image
- 移除 Python 相关基础设施文件 (entrypoint.sh, gunicorn_conf.py, Dockerfile.base)
This commit is contained in:
fawney19
2026-04-03 16:26:16 +08:00
parent 8f26e1a31f
commit 1d9c77522a
868 changed files with 1735 additions and 2433 deletions

View File

@@ -0,0 +1,8 @@
"""
认证插件模块
"""
from .api_key import ApiKeyAuthPlugin
from .base import AuthContext, AuthPlugin
__all__ = ["AuthPlugin", "AuthContext", "ApiKeyAuthPlugin"]

View File

@@ -0,0 +1,99 @@
"""
API Key认证插件
支持从header中提取API Key进行认证
"""
from __future__ import annotations
from fastapi import Request
from sqlalchemy.orm import Session
from src.core.logger import logger
from src.services.auth.service import AuthService
from src.services.usage.service import UsageService
from src.services.wallet import WalletService
from .base import AuthContext, AuthPlugin
class ApiKeyAuthPlugin(AuthPlugin):
"""
API Key认证插件
支持从x-api-key header或Authorization Bearer token中提取API Key
"""
def __init__(self) -> None:
super().__init__(name="api_key", priority=10)
def get_credentials(self, request: Request) -> str | None:
"""
从请求头中提取API Key
支持两种方式:
1. x-api-key: <key>
2. Authorization: Bearer <key>
"""
# 尝试从x-api-key header获取
api_key = request.headers.get("x-api-key")
if api_key:
return api_key
# 尝试从Authorization header获取
auth_header = request.headers.get("authorization")
if auth_header and auth_header.startswith("Bearer "):
return auth_header.replace("Bearer ", "")
return None
async def authenticate(self, request: Request, db: Session) -> AuthContext | None:
"""
使用API Key进行认证
"""
# 提取API Key
api_key = self.get_credentials(request)
if not api_key:
logger.debug("未找到API Key凭据")
return None
# 认证API Key
auth_result = AuthService.authenticate_api_key(db, api_key)
if not auth_result:
logger.warning("API Key认证失败")
return None
user, api_key_obj = auth_result
# 检查用户或独立 Key 的钱包余额可用性
access_ok, message = UsageService.check_request_balance(db, user, api_key=api_key_obj)
billing_wallet = (
WalletService.get_wallet(db, api_key_id=api_key_obj.id)
if api_key_obj.is_standalone
else WalletService.get_wallet(db, user_id=user.id)
)
# 创建认证上下文
auth_context = AuthContext(
user_id=user.id,
user_name=user.username,
api_key_id=api_key_obj.id,
api_key_name=api_key_obj.name if hasattr(api_key_obj, "name") else None,
permissions={
"can_use_api": access_ok,
"is_admin": user.is_admin if hasattr(user, "is_admin") else False,
"is_standalone_key": api_key_obj.is_standalone, # 标记是否为独立余额Key
},
billing_info={
"billing": WalletService.serialize_wallet_summary(billing_wallet),
"balance_ok": access_ok,
"message": message,
},
metadata={
"auth_method": "api_key",
"client_ip": request.client.host if request.client else "unknown",
"is_standalone": api_key_obj.is_standalone, # 在metadata中也保存一份
},
)
logger.info("API Key认证成功")
return auth_context

View File

@@ -0,0 +1,122 @@
"""
认证插件基类
定义认证插件的接口和认证上下文
"""
from __future__ import annotations
from abc import abstractmethod
from dataclasses import dataclass
from typing import Any
from fastapi import Request
from sqlalchemy.orm import Session
from ..common import BasePlugin
@dataclass
class AuthContext:
"""
认证上下文
包含认证后的用户信息和权限
"""
user_id: int
user_name: str
api_key_id: int | None = None
api_key_name: str | None = None
permissions: dict[str, bool] = None
billing_info: dict[str, Any] = None
metadata: dict[str, Any] = None
def __post_init__(self) -> None:
if self.permissions is None:
self.permissions = {}
if self.metadata is None:
self.metadata = {}
class AuthPlugin(BasePlugin):
"""
认证插件基类
所有认证插件必须继承此类并实现authenticate方法
"""
def __init__(
self,
name: str,
priority: int = 0,
version: str = "1.0.0",
author: str = "Unknown",
description: str = "",
api_version: str = "1.0",
dependencies: list[str] | None = None,
provides: list[str] | None = None,
config: dict[str, Any] | None = None,
):
"""
初始化认证插件
Args:
name: 插件名称
priority: 优先级(数字越大优先级越高)
version: 插件版本
author: 插件作者
description: 插件描述
api_version: API版本
dependencies: 依赖的其他插件
provides: 提供的服务
config: 配置字典
"""
super().__init__(
name=name,
priority=priority,
version=version,
author=author,
description=description,
api_version=api_version,
dependencies=dependencies,
provides=provides,
config=config,
)
@abstractmethod
async def authenticate(self, request: Request, db: Session) -> AuthContext | None:
"""
执行认证
Args:
request: FastAPI请求对象
db: 数据库会话
Returns:
成功返回AuthContext失败返回None
"""
pass
@abstractmethod
def get_credentials(self, request: Request) -> str | None:
"""
从请求中提取认证凭据
Args:
request: FastAPI请求对象
Returns:
认证凭据字符串如果没有找到返回None
"""
pass
def is_applicable(self, request: Request) -> bool:
"""
检查此插件是否适用于当前请求
Args:
request: FastAPI请求对象
Returns:
如果插件适用返回True
"""
# 默认情况下,如果能提取到凭据就适用
return self.get_credentials(request) is not None

View File

@@ -0,0 +1,116 @@
"""
JWT认证插件
支持JWT Bearer token认证
"""
from __future__ import annotations
import hashlib
from fastapi import Request
from sqlalchemy.orm import Session
from src.core.logger import logger
from src.models.database import User
from src.services.auth.service import AuthService
from src.services.wallet import WalletService
from .base import AuthContext, AuthPlugin
class JwtAuthPlugin(AuthPlugin):
"""
JWT认证插件
支持从Authorization Bearer header中提取JWT token进行认证
"""
def __init__(self) -> None:
super().__init__(name="jwt", priority=20) # 高优先级优先于API Key
def get_credentials(self, request: Request) -> str | None:
"""
从Authorization header中提取JWT token
支持格式: Authorization: Bearer <token>
"""
auth_header = request.headers.get("authorization")
if auth_header and auth_header.startswith("Bearer "):
return auth_header.replace("Bearer ", "")
return None
async def authenticate(self, request: Request, db: Session) -> AuthContext | None:
"""
使用JWT token进行认证
"""
# 提取JWT token
token = self.get_credentials(request)
if not token:
logger.debug("未找到JWT token")
return None
token_fingerprint = hashlib.sha256(token.encode()).hexdigest()[:12]
logger.info(f"JWT认证尝试 - 路径: {request.url.path}, token_fp={token_fingerprint}")
try:
# 验证JWT token
payload = await AuthService.verify_token(token, token_type="access")
logger.debug(f"JWT token验证成功, payload: {payload}")
# 从payload中提取用户信息
user_id = payload.get("user_id")
if not user_id:
logger.warning("JWT token中缺少用户ID")
return None
logger.debug(f"从JWT提取user_id: {user_id}, 类型: {type(user_id)}")
# 从数据库获取用户信息
user = db.query(User).filter(User.id == user_id).first()
if not user:
logger.warning(f"JWT认证失败 - 用户不存在: {user_id}")
return None
logger.debug(f"找到用户: {user.email}, is_active: {user.is_active}")
if not user.is_active:
logger.warning(f"JWT认证失败 - 用户已禁用: {user.email}")
return None
if user.is_deleted:
logger.warning(f"JWT认证失败 - 用户已删除: {user.email}")
return None
if not AuthService.token_identity_matches_user(payload, user):
logger.warning("JWT认证失败 - Token身份校验失败")
return None
wallet_access = WalletService.check_request_allowed(db, user=user, api_key=None)
# 创建认证上下文
auth_context = AuthContext(
user_id=user.id,
user_name=user.username,
permissions={
"can_use_api": wallet_access.allowed,
"is_admin": user.role.value == "admin",
},
billing_info={
"billing": WalletService.serialize_wallet_summary(
WalletService.get_wallet(db, user_id=user.id)
),
"balance_ok": wallet_access.allowed,
"message": wallet_access.message,
},
metadata={
"auth_method": "jwt",
"client_ip": request.client.host if request.client else "unknown",
"token_exp": payload.get("exp"),
},
)
logger.info("JWT认证成功")
return auth_context
except Exception as e:
logger.warning(f"JWT认证失败: {str(e)}")
return None