feat: enable audit logging for authentication and task operations

Add audit_service.log_event() calls to track key user activities:
- auth_login: successful and failed login attempts with IP/user agent
- auth_logout: single session and all sessions logout
- task_delete: task deletion with user context
- file_upload: file upload with filename, size, and type
- admin_cleanup: manual cleanup trigger with statistics

Each event captures client IP (from X-Forwarded-For/X-Real-IP headers),
user agent, and relevant metadata for compliance and debugging.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
egg
2025-12-14 12:46:20 +08:00
parent 73112db055
commit bbd68a2162
6 changed files with 226 additions and 5 deletions

View File

@@ -9,7 +9,7 @@ from pathlib import Path
import shutil
import hashlib
from fastapi import APIRouter, Depends, HTTPException, status, Query, UploadFile, File, BackgroundTasks
from fastapi import APIRouter, Depends, HTTPException, status, Query, UploadFile, File, BackgroundTasks, Request
from fastapi.responses import FileResponse, StreamingResponse
from sqlalchemy.orm import Session
import json
@@ -47,6 +47,7 @@ from app.services.task_service import task_service
from app.services.file_access_service import file_access_service
from app.services.ocr_service import OCRService
from app.services.service_pool import get_service_pool, PoolConfig
from app.services.audit_service import audit_service
# Import dual-track components
try:
@@ -67,6 +68,22 @@ logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/v2/tasks", tags=["Tasks"])
def get_client_ip(request: Request) -> str:
"""Extract client IP address from request"""
forwarded = request.headers.get("X-Forwarded-For")
if forwarded:
return forwarded.split(",")[0].strip()
real_ip = request.headers.get("X-Real-IP")
if real_ip:
return real_ip
return request.client.host if request.client else "unknown"
def get_user_agent(request: Request) -> str:
"""Extract user agent from request"""
return request.headers.get("User-Agent", "unknown")[:500]
def process_task_ocr(
task_id: str,
task_db_id: int,
@@ -518,6 +535,7 @@ async def update_task(
@router.delete("/{task_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_task(
task_id: str,
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
):
@@ -539,6 +557,20 @@ async def delete_task(
)
logger.info(f"Deleted task {task_id} for user {current_user.email}")
# Log task deletion
audit_service.log_event(
db=db,
event_type="task_delete",
event_category="task",
description=f"Task deleted",
user_id=current_user.id,
ip_address=get_client_ip(request),
user_agent=get_user_agent(request),
resource_type="task",
resource_id=task_id,
success=True
)
return None