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

@@ -390,7 +390,7 @@ async def root():
# Include V2 API routers
from app.routers import auth, tasks, admin, translate
from fastapi import UploadFile, File, Depends, HTTPException, status
from fastapi import UploadFile, File, Depends, HTTPException, status, Request
from sqlalchemy.orm import Session
import hashlib
@@ -399,6 +399,23 @@ from app.models.user import User
from app.models.task import TaskFile
from app.schemas.task import UploadResponse, TaskStatusEnum
from app.services.task_service import task_service
from app.services.audit_service import audit_service
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]
app.include_router(auth.router)
app.include_router(tasks.router)
@@ -409,6 +426,7 @@ app.include_router(translate.router)
# File upload endpoint
@app.post("/api/v2/upload", response_model=UploadResponse, tags=["Upload"], summary="Upload file for OCR")
async def upload_file(
request: Request,
file: UploadFile = File(..., description="File to upload (PNG, JPG, PDF, etc.)"),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
@@ -470,6 +488,25 @@ async def upload_file(
logger.info(f"Uploaded file {file.filename} ({file_size} bytes) for task {task.task_id}, user {current_user.email}")
# Log file upload event
audit_service.log_event(
db=db,
event_type="file_upload",
event_category="file",
description=f"File uploaded: {file.filename} ({file_size} bytes)",
user_id=current_user.id,
ip_address=get_client_ip(request),
user_agent=get_user_agent(request),
resource_type="task",
resource_id=task.task_id,
success=True,
metadata={
"filename": file.filename,
"file_size": file_size,
"file_type": file.content_type
}
)
return {
"task_id": task.task_id,
"filename": file.filename,