mirror of
https://github.com/fawney19/Aether.git
synced 2026-01-03 00:02:28 +08:00
- Replace BaseHTTPMiddleware with pure ASGI implementation in plugin middleware for better streaming response handling - Add trusted proxy count configuration for client IP extraction in reverse proxy environments - Implement audit log cleanup scheduler with configurable retention period - Replace plaintext token logging with SHA256 hash fingerprints for security - Fix database session lifecycle management in middleware - Improve request tracing and error logging throughout the system - Add comprehensive tests for pipeline architecture
105 lines
3.4 KiB
Python
105 lines
3.4 KiB
Python
"""
|
||
JWT认证插件
|
||
支持JWT Bearer token认证
|
||
"""
|
||
|
||
import hashlib
|
||
from typing import Optional
|
||
|
||
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 .base import AuthContext, AuthPlugin
|
||
|
||
|
||
|
||
class JwtAuthPlugin(AuthPlugin):
|
||
"""
|
||
JWT认证插件
|
||
支持从Authorization Bearer header中提取JWT token进行认证
|
||
"""
|
||
|
||
def __init__(self):
|
||
super().__init__(name="jwt", priority=20) # 高优先级,优先于API Key
|
||
|
||
def get_credentials(self, request: Request) -> Optional[str]:
|
||
"""
|
||
从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) -> Optional[AuthContext]:
|
||
"""
|
||
使用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
|
||
|
||
# 创建认证上下文
|
||
auth_context = AuthContext(
|
||
user_id=user.id,
|
||
user_name=user.username,
|
||
permissions={"can_use_api": True, "is_admin": user.role.value == "admin"},
|
||
quota_info={
|
||
"quota_usd": user.quota_usd,
|
||
"used_usd": user.used_usd,
|
||
"remaining_usd": (
|
||
None if user.quota_usd is None else user.quota_usd - user.used_usd
|
||
),
|
||
"quota_ok": True, # JWT用户通常已经通过前端验证
|
||
},
|
||
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
|