Files
crm-system/app/deps.py
T

97 lines
3.0 KiB
Python
Raw Normal View History

"""FastAPI dependencies: auth, db, tenant context, RBAC."""
from __future__ import annotations
import uuid
from typing import Any
import redis.asyncio as aioredis
from fastapi import Depends, HTTPException, Request, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.config import get_settings
from app.core.auth import get_redis, get_session_data
from app.core.db import get_db, set_tenant_context
from app.models.user import User
async def get_redis_dep() -> aioredis.Redis:
"""FastAPI dependency for Redis client."""
return get_redis()
async def get_current_user(
request: Request,
db: AsyncSession = Depends(get_db),
redis: aioredis.Redis = Depends(get_redis_dep),
) -> dict[str, Any]:
"""Get the current authenticated user from session cookie.
Returns session data dict with user_id, tenant_id, email, name, role.
"""
settings = get_settings()
session_id = request.cookies.get(settings.session_cookie_name)
if not session_id:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail={"detail": "Not authenticated", "code": "not_authenticated"},
)
session_data = await get_session_data(redis, session_id)
if session_data is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail={"detail": "Session expired or invalid", "code": "session_invalid"},
)
if not session_data.get("is_active", True):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail={"detail": "User account deactivated", "code": "user_inactive"},
)
# Set RLS tenant context
tenant_id = uuid.UUID(session_data["tenant_id"])
await set_tenant_context(db, tenant_id)
return session_data
async def require_admin(
current_user: dict[str, Any] = Depends(get_current_user),
) -> dict[str, Any]:
"""Require admin role."""
if current_user.get("role") != "admin":
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail={"detail": "Admin access required", "code": "forbidden"},
)
return current_user
async def require_write(
current_user: dict[str, Any] = Depends(get_current_user),
) -> dict[str, Any]:
"""Require write permission (admin or editor)."""
role = current_user.get("role", "viewer")
if role not in ("admin", "editor"):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail={"detail": "Write access required", "code": "forbidden"},
)
return current_user
async def get_tenant_id(
current_user: dict[str, Any] = Depends(get_current_user),
) -> uuid.UUID:
"""Extract tenant_id from current user session."""
return uuid.UUID(current_user["tenant_id"])
async def get_current_user_id(
current_user: dict[str, Any] = Depends(get_current_user),
) -> uuid.UUID:
"""Extract user_id from current user session."""
return uuid.UUID(current_user["user_id"])