2026-06-01 17:32:18 +08:00
|
|
|
from fastapi import Header, Request, Security
|
|
|
|
|
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
2026-06-01 09:25:26 +08:00
|
|
|
|
|
|
|
|
from app.core.context import UserContext
|
|
|
|
|
from app.core.exceptions import AppError
|
2026-06-01 14:28:43 +08:00
|
|
|
from app.services.external_auth_service import ExternalAuthService
|
2026-06-01 09:25:26 +08:00
|
|
|
|
2026-06-01 17:32:18 +08:00
|
|
|
bearer_scheme = HTTPBearer(auto_error=False, description="Django 用户中心 access token")
|
|
|
|
|
|
2026-06-01 09:25:26 +08:00
|
|
|
|
|
|
|
|
async def get_user_context(
|
|
|
|
|
request: Request,
|
2026-06-01 17:32:18 +08:00
|
|
|
credentials: HTTPAuthorizationCredentials | None = Security(bearer_scheme),
|
2026-06-01 09:25:26 +08:00
|
|
|
x_entry_scene: str | None = Header(default=None, alias="X-Entry-Scene"),
|
|
|
|
|
x_request_id: str | None = Header(default=None, alias="X-Request-Id"),
|
|
|
|
|
) -> UserContext:
|
2026-06-01 17:32:18 +08:00
|
|
|
"""用户校验:只接受宿主系统 access token,并转发 Django 用户中心 `/me` 获取真实用户。"""
|
|
|
|
|
if not credentials or not credentials.credentials.strip():
|
|
|
|
|
raise AppError("AUTH_CREDENTIAL_REQUIRED", "Authorization header is required", 401)
|
2026-06-01 09:25:26 +08:00
|
|
|
|
2026-06-01 17:32:18 +08:00
|
|
|
user = await ExternalAuthService().authenticate(request)
|
2026-06-01 09:25:26 +08:00
|
|
|
return UserContext(
|
2026-06-01 17:32:18 +08:00
|
|
|
user_id=user.user_id,
|
|
|
|
|
tenant_id=user.tenant_id,
|
|
|
|
|
role=user.role,
|
2026-06-01 09:25:26 +08:00
|
|
|
entry_scene=x_entry_scene,
|
|
|
|
|
request_id=x_request_id,
|
|
|
|
|
ip_address=request.client.host if request.client else None,
|
|
|
|
|
user_agent=request.headers.get("User-Agent"),
|
2026-06-01 17:32:18 +08:00
|
|
|
username=user.username,
|
|
|
|
|
display_name=user.display_name,
|
|
|
|
|
auth_source=user.source,
|
|
|
|
|
profile=user.profile,
|
2026-06-01 09:25:26 +08:00
|
|
|
)
|