166 lines
5.8 KiB
Python
166 lines
5.8 KiB
Python
"""
|
|
API key management routes.
|
|
"""
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.orm import Session
|
|
from typing import List, Optional
|
|
from datetime import datetime
|
|
from ...shared.config.database import get_db
|
|
from ...shared.config.logging_config import get_logger
|
|
from ...security.middleware.auth import get_current_user, authorize_roles
|
|
from ...auth.models.user import User
|
|
from ..services.api_key_service import api_key_service
|
|
from ..models.api_key import APIKey
|
|
from ...shared.utils.response_helpers import success_response
|
|
from pydantic import BaseModel
|
|
|
|
logger = get_logger(__name__)
|
|
router = APIRouter(prefix='/api-keys', tags=['api-keys'])
|
|
|
|
class CreateAPIKeyRequest(BaseModel):
|
|
name: str
|
|
scopes: List[str]
|
|
description: Optional[str] = None
|
|
rate_limit: int = 100
|
|
expires_at: Optional[str] = None
|
|
|
|
class UpdateAPIKeyRequest(BaseModel):
|
|
name: Optional[str] = None
|
|
scopes: Optional[List[str]] = None
|
|
description: Optional[str] = None
|
|
rate_limit: Optional[int] = None
|
|
expires_at: Optional[str] = None
|
|
|
|
@router.post('/')
|
|
async def create_api_key(
|
|
key_data: CreateAPIKeyRequest,
|
|
current_user: User = Depends(authorize_roles('admin')),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""Create a new API key."""
|
|
try:
|
|
expires_at = None
|
|
if key_data.expires_at:
|
|
expires_at = datetime.fromisoformat(key_data.expires_at.replace('Z', '+00:00'))
|
|
|
|
api_key, plain_key = api_key_service.create_api_key(
|
|
db=db,
|
|
name=key_data.name,
|
|
scopes=key_data.scopes,
|
|
created_by=current_user.id,
|
|
description=key_data.description,
|
|
rate_limit=key_data.rate_limit,
|
|
expires_at=expires_at
|
|
)
|
|
|
|
return success_response(
|
|
data={
|
|
'api_key': {
|
|
'id': api_key.id,
|
|
'name': api_key.name,
|
|
'key_prefix': api_key.key_prefix,
|
|
'scopes': api_key.scopes,
|
|
'rate_limit': api_key.rate_limit,
|
|
'expires_at': api_key.expires_at.isoformat() if api_key.expires_at else None
|
|
},
|
|
'key': plain_key # Return plain key only on creation
|
|
},
|
|
message='API key created successfully. Save this key securely - it will not be shown again.'
|
|
)
|
|
except Exception as e:
|
|
logger.error(f'Error creating API key: {str(e)}', exc_info=True)
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
@router.get('/')
|
|
async def get_api_keys(
|
|
current_user: User = Depends(authorize_roles('admin')),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""Get all API keys."""
|
|
try:
|
|
api_keys = db.query(APIKey).order_by(APIKey.created_at.desc()).all()
|
|
|
|
return success_response(data={
|
|
'api_keys': [{
|
|
'id': k.id,
|
|
'name': k.name,
|
|
'key_prefix': k.key_prefix,
|
|
'scopes': k.scopes,
|
|
'rate_limit': k.rate_limit,
|
|
'is_active': k.is_active,
|
|
'last_used_at': k.last_used_at.isoformat() if k.last_used_at else None,
|
|
'expires_at': k.expires_at.isoformat() if k.expires_at else None,
|
|
'created_at': k.created_at.isoformat() if k.created_at else None
|
|
} for k in api_keys]
|
|
})
|
|
except Exception as e:
|
|
logger.error(f'Error getting API keys: {str(e)}', exc_info=True)
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
@router.put('/{key_id}')
|
|
async def update_api_key(
|
|
key_id: int,
|
|
key_data: UpdateAPIKeyRequest,
|
|
current_user: User = Depends(authorize_roles('admin')),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""Update an API key."""
|
|
try:
|
|
expires_at = None
|
|
if key_data.expires_at:
|
|
expires_at = datetime.fromisoformat(key_data.expires_at.replace('Z', '+00:00'))
|
|
|
|
api_key = api_key_service.update_api_key(
|
|
db=db,
|
|
key_id=key_id,
|
|
name=key_data.name,
|
|
scopes=key_data.scopes,
|
|
description=key_data.description,
|
|
rate_limit=key_data.rate_limit,
|
|
expires_at=expires_at
|
|
)
|
|
|
|
if not api_key:
|
|
raise HTTPException(status_code=404, detail='API key not found')
|
|
|
|
return success_response(
|
|
data={
|
|
'api_key': {
|
|
'id': api_key.id,
|
|
'name': api_key.name,
|
|
'key_prefix': api_key.key_prefix,
|
|
'scopes': api_key.scopes,
|
|
'rate_limit': api_key.rate_limit,
|
|
'is_active': api_key.is_active,
|
|
'expires_at': api_key.expires_at.isoformat() if api_key.expires_at else None,
|
|
'created_at': api_key.created_at.isoformat() if api_key.created_at else None
|
|
}
|
|
},
|
|
message='API key updated successfully'
|
|
)
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
logger.error(f'Error updating API key: {str(e)}', exc_info=True)
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
@router.delete('/{key_id}')
|
|
async def revoke_api_key(
|
|
key_id: int,
|
|
current_user: User = Depends(authorize_roles('admin')),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""Revoke an API key."""
|
|
try:
|
|
success = api_key_service.revoke_api_key(db=db, key_id=key_id)
|
|
if not success:
|
|
raise HTTPException(status_code=404, detail='API key not found')
|
|
|
|
return success_response(message='API key revoked successfully')
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
logger.error(f'Error revoking API key: {str(e)}', exc_info=True)
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|