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

@@ -17,6 +17,7 @@ from app.models.user import User
from app.models.session import Session as UserSession
from app.schemas.auth import LoginRequest, Token, UserResponse
from app.services.external_auth_service import external_auth_service
from app.services.audit_service import audit_service
logger = logging.getLogger(__name__)
@@ -66,6 +67,17 @@ async def login(
logger.warning(
f"External auth failed for user {login_data.username}: {error_msg}"
)
# Log failed login attempt
audit_service.log_event(
db=db,
event_type="auth_login",
event_category="authentication",
description=f"Login failed for {login_data.username}: {error_msg}",
ip_address=get_client_ip(request),
user_agent=get_user_agent(request),
success=False,
error_message=error_msg
)
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=error_msg or "Authentication failed",
@@ -151,6 +163,20 @@ async def login(
expires_delta=internal_token_expires
)
# Log successful login
audit_service.log_event(
db=db,
event_type="auth_login",
event_category="authentication",
description=f"User logged in successfully",
user_id=user.id,
ip_address=get_client_ip(request),
user_agent=get_user_agent(request),
resource_type="session",
resource_id=str(session.id),
success=True
)
return {
"access_token": internal_access_token,
"token_type": "bearer",
@@ -165,6 +191,7 @@ async def login(
@router.post("/logout", summary="User logout")
async def logout(
request: Request,
session_id: Optional[int] = None,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
@@ -174,9 +201,6 @@ async def logout(
- **session_id**: Session ID to logout (optional, logs out all if not provided)
"""
# TODO: Implement proper current_user dependency from JWT token
# For now, this is a placeholder
if session_id:
# Logout specific session
session = db.query(UserSession).filter(
@@ -188,6 +212,20 @@ async def logout(
db.delete(session)
db.commit()
logger.info(f"Logged out session {session_id} for user {current_user.email}")
# Log logout event
audit_service.log_event(
db=db,
event_type="auth_logout",
event_category="authentication",
description=f"User logged out session {session_id}",
user_id=current_user.id,
ip_address=get_client_ip(request),
user_agent=get_user_agent(request),
resource_type="session",
resource_id=str(session_id),
success=True
)
return {"message": "Logged out successfully"}
else:
raise HTTPException(
@@ -206,6 +244,19 @@ async def logout(
db.commit()
logger.info(f"Logged out all {count} sessions for user {current_user.email}")
# Log logout event
audit_service.log_event(
db=db,
event_type="auth_logout",
event_category="authentication",
description=f"User logged out all {count} sessions",
user_id=current_user.id,
ip_address=get_client_ip(request),
user_agent=get_user_agent(request),
success=True,
metadata={"sessions_count": count}
)
return {"message": f"Logged out {count} sessions"}