Files
boc/landvex-admin/backend/app/api/deps.py
T

84 lines
2.7 KiB
Python
Raw Normal View History

"""API dependencies for authentication, authorization, and tenant resolution."""
from typing import Annotated
from uuid import UUID
from fastapi import Depends, HTTPException, Header, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.orm import Session
from app.database import get_db
from app.core.security import decode_token
from app.models.user import User
from app.models.tenant import Tenant
from app.core.permissions import has_permission
security = HTTPBearer()
async def get_current_user(
credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)],
db: Session = Depends(get_db),
) -> User:
"""Validate JWT and return current user."""
try:
payload = decode_token(credentials.credentials)
user_id = UUID(payload["sub"])
except Exception:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials",
headers={"WWW-Authenticate": "Bearer"},
)
user = db.query(User).filter(User.id == user_id).first()
if not user or user.status != "active":
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="User not found or inactive",
)
return user
async def get_current_tenant(
x_tenant_id: Annotated[UUID, Header(..., alias="X-Tenant-ID")],
user: User = Depends(get_current_user),
) -> Tenant:
"""Validate user has access to the specified tenant."""
if user.tenant_id != x_tenant_id:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Access denied to this tenant",
)
return user.tenant
class RequirePermission:
"""Dependency factory for permission checking."""
def __init__(self, permission: str):
self.permission = permission
async def __call__(self, user: User = Depends(get_current_user)) -> User:
user_perms = set()
for role in user.roles:
user_perms.update(role.permissions)
if not has_permission(user_perms, self.permission):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=f"Missing permission: {self.permission}",
)
return user
# Common permission dependencies
RequireAdmin = Depends(RequirePermission("users.update"))
RequireUserRead = Depends(RequirePermission("users.read"))
RequireTenantManage = Depends(RequirePermission("tenants.manage"))
RequireBillingRead = Depends(RequirePermission("billing.read"))
RequireAuditRead = Depends(RequirePermission("audit.read"))
RequireReportCreate = Depends(RequirePermission("reports.create"))
RequireApiKeyCreate = Depends(RequirePermission("api_keys.create"))