73 lines
2.9 KiB
Python
73 lines
2.9 KiB
Python
from fastapi import HTTPException, Depends, status, Request
|
|
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
|
import httpx
|
|
import structlog
|
|
from typing import Dict, Any, Optional
|
|
|
|
from app.core.config import settings
|
|
|
|
logger = structlog.get_logger()
|
|
security = HTTPBearer(auto_error=False) # ✅ Don't auto-error, we'll handle manually
|
|
|
|
class AuthInfo:
|
|
"""Authentication information"""
|
|
def __init__(self, user_id: str, email: str, tenant_id: str, roles: list):
|
|
self.user_id = user_id
|
|
self.email = email
|
|
self.tenant_id = tenant_id
|
|
self.roles = roles
|
|
|
|
async def get_current_user(
|
|
request: Request,
|
|
credentials: Optional[HTTPAuthorizationCredentials] = Depends(security)
|
|
) -> AuthInfo:
|
|
"""Get current user from gateway headers or token verification"""
|
|
|
|
# ✅ OPTION 1: Check for gateway headers (preferred when using gateway)
|
|
user_id = request.headers.get("X-User-ID")
|
|
email = request.headers.get("X-User-Email")
|
|
tenant_id = request.headers.get("X-Tenant-ID")
|
|
roles_header = request.headers.get("X-User-Roles", "")
|
|
|
|
if user_id and email and tenant_id:
|
|
# Gateway already authenticated the user
|
|
roles = roles_header.split(",") if roles_header else ["user"]
|
|
logger.info("Authenticated via gateway headers", user_id=user_id, email=email)
|
|
return AuthInfo(user_id, email, tenant_id, roles)
|
|
|
|
# ✅ OPTION 2: Direct token verification (when not using gateway)
|
|
if not credentials:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
detail="Authentication required (no token or gateway headers)"
|
|
)
|
|
|
|
try:
|
|
async with httpx.AsyncClient(timeout=5.0) as client:
|
|
response = await client.post(
|
|
f"{settings.AUTH_SERVICE_URL}/api/v1/auth/verify",
|
|
headers={"Authorization": f"Bearer {credentials.credentials}"}
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
user_data = response.json()
|
|
logger.info("Authenticated via direct token", user_id=user_data.get("user_id"))
|
|
return AuthInfo(
|
|
user_id=user_data["user_id"],
|
|
email=user_data["email"],
|
|
tenant_id=user_data["tenant_id"],
|
|
roles=user_data.get("roles", ["user"])
|
|
)
|
|
else:
|
|
logger.warning("Token verification failed", status_code=response.status_code)
|
|
raise HTTPException(
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
detail="Invalid authentication credentials"
|
|
)
|
|
except httpx.RequestError as e:
|
|
logger.error("Auth service unavailable", error=str(e))
|
|
raise HTTPException(
|
|
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
|
detail="Authentication service unavailable"
|
|
)
|