""" 认证中间件(ASGI)- 管理端专用 - 验证 Authorization: Bearer - 校验管理员存在性与状态 - 在 scope 中注入 verified_admin_id 供下游中间件使用 """ from app.core.security import verify_token from app.database import SessionLocal from app.models.admin import Admin from fastapi.responses import JSONResponse from app.core.logger import logger, get_logger_by_path EXEMPT_PATHS = [ "/", "/admin/login", "/health", "/docs", "/redoc", "/openapi.json", ] class AuthValidationASGIMiddleware: def __init__(self, app): self.app = app async def __call__(self, scope, receive, send): # 仅处理 HTTP 请求 if scope.get("type") != "http": await self.app(scope, receive, send) return path = scope.get("path", "") method = scope.get("method", "").upper() # 根据路径选择对应的logger auth_logger = get_logger_by_path(path) # 跳过不需要验证的路径或 CORS 预检 if method == "OPTIONS" or any(path.startswith(p) for p in EXEMPT_PATHS): await self.app(scope, receive, send) return headers = {k.decode("utf-8"): v.decode("utf-8") for k, v in scope.get("headers", [])} auth_header = headers.get("authorization", "") or headers.get("Authorization", "") # 获取header中的用户信息用于组合校验 header_user_id = headers.get("x-user-id") or headers.get("X-User-Id") header_user_name = headers.get("x-user-name") or headers.get("X-User-Name") # 临时调试日志:记录客户端传来的鉴别头,帮助定位客户端是否传递了 X-User-Id/X-User-Name 或 Authorization try: auth_logger.debug(f"[AuthMiddleware][DEBUG HEADERS] path={path} method={method} X-User-Id={header_user_id} X-User-Name={header_user_name} AuthorizationPresent={bool(auth_header)}") except Exception: auth_logger.debug("[AuthMiddleware][DEBUG HEADERS] failed to read headers") if not auth_header or not auth_header.startswith("Bearer "): resp = JSONResponse(status_code=401, content={"code": 401, "msg": "认证信息缺失或无效"}) await resp(scope, receive, send) return token = auth_header[7:] payload = verify_token(token) if not payload: resp = JSONResponse(status_code=401, content={"code": 401, "msg": "认证信息无效或已过期"}) await resp(scope, receive, send) return username = payload.get("sub") if not username: resp = JSONResponse(status_code=401, content={"code": 401, "msg": "认证信息无效"}) await resp(scope, receive, send) return auth_logger.debug(f"[AuthMiddleware][DEBUG] Starting authentication for username: {username}, path: {path}") # 查询管理员 db = SessionLocal() try: admin = db.query(Admin).filter(Admin.username == username).first() if admin: auth_logger.debug(f"[AuthMiddleware][DEBUG] Found admin: {admin.username} (ID: {admin.id})") # 验证header中的用户信息是否匹配(组合校验) if header_user_id and header_user_name: try: header_user_id_int = int(header_user_id) if header_user_id_int != admin.id or header_user_name != admin.username: resp = JSONResponse(status_code=401, content={"code": 401, "msg": "用户信息校验失败"}) await resp(scope, receive, send) return except ValueError: resp = JSONResponse(status_code=401, content={"code": 401, "msg": "用户信息格式错误"}) await resp(scope, receive, send) return else: resp = JSONResponse(status_code=401, content={"code": 401, "msg": "缺少用户信息"}) await resp(scope, receive, send) return if admin.status != 1: resp = JSONResponse(status_code=403, content={"code": 403, "msg": "管理员账号已被禁用"}) await resp(scope, receive, send) return scope["verified_admin_id"] = admin.id scope["verified_username"] = admin.username scope["verified_is_admin"] = True auth_logger.debug(f"[AuthMiddleware][DEBUG] Set verified_admin_id: {admin.id} for admin: {admin.username}") await self.app(scope, receive, send) return # 未找到对应管理员 auth_logger.debug(f"[AuthMiddleware][DEBUG] No admin found for username: {username}") resp = JSONResponse(status_code=401, content={"code": 401, "msg": "认证失败:管理员不存在"}) await resp(scope, receive, send) return except Exception as e: auth_logger.exception(f"[AuthMiddleware][ERROR] Exception during authentication: {e}") resp = JSONResponse(status_code=500, content={"code": 500, "msg": "认证服务异常"}) await resp(scope, receive, send) return finally: db.close()