Files
TJWaterServerBinary/app/core/audit.py

147 lines
3.7 KiB
Python

"""
审计日志模块
记录系统关键操作,用于安全审计和合规追踪
"""
from typing import Optional
from datetime import datetime
import logging
from uuid import UUID
logger = logging.getLogger(__name__)
class AuditAction:
"""审计操作类型常量"""
# 认证相关
LOGIN = "LOGIN"
LOGOUT = "LOGOUT"
REGISTER = "REGISTER"
PASSWORD_CHANGE = "PASSWORD_CHANGE"
# 数据操作
CREATE = "CREATE"
READ = "READ"
UPDATE = "UPDATE"
DELETE = "DELETE"
# 权限相关
PERMISSION_CHANGE = "PERMISSION_CHANGE"
ROLE_CHANGE = "ROLE_CHANGE"
# 系统操作
CONFIG_CHANGE = "CONFIG_CHANGE"
SYSTEM_START = "SYSTEM_START"
SYSTEM_STOP = "SYSTEM_STOP"
async def log_audit_event(
action: str,
user_id: Optional[UUID] = None,
project_id: Optional[UUID] = None,
resource_type: Optional[str] = None,
resource_id: Optional[str] = None,
ip_address: Optional[str] = None,
request_method: Optional[str] = None,
request_path: Optional[str] = None,
request_data: Optional[dict] = None,
response_status: Optional[int] = None,
session=None,
):
"""
记录审计日志
Args:
action: 操作类型
user_id: 用户ID
project_id: 项目ID
resource_type: 资源类型
resource_id: 资源ID
ip_address: IP地址
request_method: 请求方法
request_path: 请求路径
request_data: 请求数据(敏感字段需脱敏)
response_status: 响应状态码
session: 元数据库会话(可选)
"""
from app.infra.db.metadata.database import SessionLocal
from app.infra.repositories.audit_repository import AuditRepository
if request_data:
request_data = sanitize_sensitive_data(request_data)
if session is None:
async with SessionLocal() as session:
audit_repo = AuditRepository(session)
await audit_repo.create_log(
user_id=user_id,
project_id=project_id,
action=action,
resource_type=resource_type,
resource_id=resource_id,
ip_address=ip_address,
request_method=request_method,
request_path=request_path,
request_data=request_data,
response_status=response_status,
)
else:
audit_repo = AuditRepository(session)
await audit_repo.create_log(
user_id=user_id,
project_id=project_id,
action=action,
resource_type=resource_type,
resource_id=resource_id,
ip_address=ip_address,
request_method=request_method,
request_path=request_path,
request_data=request_data,
response_status=response_status,
)
logger.info(
"Audit log created: action=%s, user=%s, project=%s, resource=%s:%s",
action,
user_id,
project_id,
resource_type,
resource_id,
)
def sanitize_sensitive_data(data: dict) -> dict:
"""
脱敏敏感数据
Args:
data: 原始数据
Returns:
脱敏后的数据
"""
sensitive_fields = [
"password",
"passwd",
"pwd",
"secret",
"token",
"api_key",
"apikey",
"credit_card",
"ssn",
"social_security",
]
sanitized = data.copy()
for key in sanitized:
if isinstance(sanitized[key], dict):
sanitized[key] = sanitize_sensitive_data(sanitized[key])
elif any(sensitive in key.lower() for sensitive in sensitive_fields):
sanitized[key] = "***REDACTED***"
return sanitized