154 lines
4.5 KiB
Python
154 lines
4.5 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, status, Query
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
import logging
|
|
|
|
from database import get_session, User
|
|
from core.dependencies import get_current_user, require_role
|
|
from services.api_key import ApiKeyService, api_key_to_response
|
|
from schemas.api_key import (
|
|
ApiKeyCreate,
|
|
ApiKeyCreatedResponse,
|
|
ApiKeyResponse,
|
|
ApiKeyList,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
router = APIRouter(prefix="/api-keys", tags=["API Keys Management"])
|
|
|
|
|
|
@router.post(
|
|
"",
|
|
response_model=ApiKeyCreatedResponse,
|
|
status_code=status.HTTP_201_CREATED,
|
|
dependencies=[Depends(require_role("admin", "super_admin"))],
|
|
)
|
|
async def create_api_key(
|
|
data: ApiKeyCreate,
|
|
session: AsyncSession = Depends(get_session),
|
|
user: User = Depends(get_current_user),
|
|
):
|
|
service = ApiKeyService(session)
|
|
|
|
api_key_obj, api_key_plain = await service.create_api_key(
|
|
name=data.name,
|
|
description=data.description,
|
|
created_by=user.email,
|
|
user_id=user.id,
|
|
expires_in_days=data.expires_in_days,
|
|
rate_limit_per_minute=data.rate_limit_per_minute,
|
|
allowed_endpoints=data.allowed_endpoints,
|
|
)
|
|
|
|
logger.info(f" Clé API créée par {user.email}: {data.name}")
|
|
|
|
response_data = api_key_to_response(api_key_obj)
|
|
response_data["api_key"] = api_key_plain
|
|
|
|
return ApiKeyCreatedResponse(**response_data)
|
|
|
|
|
|
@router.get("", response_model=ApiKeyList)
|
|
async def list_api_keys(
|
|
include_revoked: bool = Query(False, description="Inclure les clés révoquées"),
|
|
session: AsyncSession = Depends(get_session),
|
|
user: User = Depends(get_current_user),
|
|
):
|
|
service = ApiKeyService(session)
|
|
|
|
user_id = None if user.role in ["admin", "super_admin"] else user.id
|
|
|
|
keys = await service.list_api_keys(include_revoked=include_revoked, user_id=user_id)
|
|
|
|
items = [ApiKeyResponse(**api_key_to_response(k)) for k in keys]
|
|
|
|
return ApiKeyList(total=len(items), items=items)
|
|
|
|
|
|
@router.get("/{key_id}", response_model=ApiKeyResponse)
|
|
async def get_api_key(
|
|
key_id: str,
|
|
session: AsyncSession = Depends(get_session),
|
|
user: User = Depends(get_current_user),
|
|
):
|
|
"""Récupérer une clé API par son ID"""
|
|
service = ApiKeyService(session)
|
|
|
|
api_key_obj = await service.get_by_id(key_id)
|
|
|
|
if not api_key_obj:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=f"Clé API {key_id} introuvable",
|
|
)
|
|
|
|
if user.role not in ["admin", "super_admin"]:
|
|
if api_key_obj.user_id != user.id:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
detail="Accès refusé à cette clé",
|
|
)
|
|
|
|
return ApiKeyResponse(**api_key_to_response(api_key_obj))
|
|
|
|
|
|
@router.delete("/{key_id}", status_code=status.HTTP_200_OK)
|
|
async def revoke_api_key(
|
|
key_id: str,
|
|
session: AsyncSession = Depends(get_session),
|
|
user: User = Depends(get_current_user),
|
|
):
|
|
service = ApiKeyService(session)
|
|
|
|
api_key_obj = await service.get_by_id(key_id)
|
|
|
|
if not api_key_obj:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=f"Clé API {key_id} introuvable",
|
|
)
|
|
|
|
if user.role not in ["admin", "super_admin"]:
|
|
if api_key_obj.user_id != user.id:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
detail="Accès refusé à cette clé",
|
|
)
|
|
|
|
success = await service.revoke_api_key(key_id)
|
|
|
|
if not success:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail="Erreur lors de la révocation",
|
|
)
|
|
|
|
logger.info(f" Clé API révoquée par {user.email}: {api_key_obj.name}")
|
|
|
|
return {
|
|
"success": True,
|
|
"message": f"Clé API '{api_key_obj.name}' révoquée avec succès",
|
|
}
|
|
|
|
|
|
@router.post("/verify", status_code=status.HTTP_200_OK)
|
|
async def verify_api_key_endpoint(
|
|
api_key: str = Query(..., description="Clé API à vérifier"),
|
|
session: AsyncSession = Depends(get_session),
|
|
):
|
|
service = ApiKeyService(session)
|
|
|
|
api_key_obj = await service.verify_api_key(api_key)
|
|
|
|
if not api_key_obj:
|
|
return {
|
|
"valid": False,
|
|
"message": "Clé API invalide, expirée ou révoquée",
|
|
}
|
|
|
|
return {
|
|
"valid": True,
|
|
"message": "Clé API valide",
|
|
"key_name": api_key_obj.name,
|
|
"rate_limit": api_key_obj.rate_limit_per_minute,
|
|
"expires_at": api_key_obj.expires_at,
|
|
}
|