"""FastAPI 依赖:解析 JWT 并构建 AuthContext。""" from __future__ import annotations from typing import Annotated from fastapi import Header, Request from app.gateway.jwt_service import decode_token from app.gateway.rbac import assert_agent_access from app.model.schemas import AgentType, AuthContext from app.utils.exceptions import UnauthorizedError def _parse_bearer(authorization: str | None) -> str: if not authorization: raise UnauthorizedError("缺少 Authorization 头", error_code="AUTH_401_MISSING") scheme, _, token = authorization.partition(" ") if scheme.lower() != "bearer" or not token: raise UnauthorizedError("Authorization 格式错误", error_code="AUTH_401_FORMAT") return token def get_auth_context( request: Request, authorization: Annotated[str | None, Header()] = None, x_agent_type: Annotated[str | None, Header(alias="X-Agent-Type")] = None, ) -> AuthContext: token = _parse_bearer(authorization) payload = decode_token(token) trace_id = getattr(request.state, "trace_id", None) or request.headers.get("X-Trace-Id", "unknown") if not x_agent_type: raise UnauthorizedError("缺少 X-Agent-Type 头", error_code="AUTH_401_AGENT_TYPE") try: agent_type: AgentType = x_agent_type # type: ignore[assignment] if agent_type not in ("customer", "advisor", "analyst", "risk"): raise ValueError except ValueError as exc: raise UnauthorizedError("X-Agent-Type 无效", error_code="AUTH_401_AGENT_TYPE") from exc ctx = AuthContext( sub=str(payload["sub"]), token_type=payload["token_type"], roles=list(payload.get("roles") or []), permissions=list(payload.get("permissions") or []), tenant_id=str(payload.get("tenant_id") or "default"), trace_id=trace_id, agent_type=agent_type, jti=str(payload.get("jti") or ""), customer_id=payload.get("customer_id"), ) assert_agent_access(ctx) return ctx