重构数据库连接管理,添加元数据支持
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
import logging
|
||||
from uuid import UUID
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -38,18 +39,16 @@ class AuditAction:
|
||||
|
||||
async def log_audit_event(
|
||||
action: str,
|
||||
user_id: Optional[int] = None,
|
||||
username: Optional[str] = None,
|
||||
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,
|
||||
user_agent: Optional[str] = None,
|
||||
request_method: Optional[str] = None,
|
||||
request_path: Optional[str] = None,
|
||||
request_data: Optional[dict] = None,
|
||||
response_status: Optional[int] = None,
|
||||
error_message: Optional[str] = None,
|
||||
db=None, # 新增:可选的数据库实例
|
||||
session=None,
|
||||
):
|
||||
"""
|
||||
记录审计日志
|
||||
@@ -57,67 +56,60 @@ async def log_audit_event(
|
||||
Args:
|
||||
action: 操作类型
|
||||
user_id: 用户ID
|
||||
username: 用户名
|
||||
project_id: 项目ID
|
||||
resource_type: 资源类型
|
||||
resource_id: 资源ID
|
||||
ip_address: IP地址
|
||||
user_agent: User-Agent
|
||||
request_method: 请求方法
|
||||
request_path: 请求路径
|
||||
request_data: 请求数据(敏感字段需脱敏)
|
||||
response_status: 响应状态码
|
||||
error_message: 错误消息
|
||||
db: 数据库实例(可选,如果不提供则尝试获取)
|
||||
session: 元数据库会话(可选)
|
||||
"""
|
||||
from app.infra.db.metadata.database import SessionLocal
|
||||
from app.infra.repositories.audit_repository import AuditRepository
|
||||
|
||||
try:
|
||||
# 脱敏敏感数据
|
||||
if request_data:
|
||||
request_data = sanitize_sensitive_data(request_data)
|
||||
|
||||
# 如果没有提供数据库实例,尝试从全局获取
|
||||
if db is None:
|
||||
try:
|
||||
from app.infra.db.postgresql.database import db as default_db
|
||||
|
||||
# 仅当连接池已初始化时使用
|
||||
if default_db.pool:
|
||||
db = default_db
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# 如果仍然没有数据库实例
|
||||
if db is None:
|
||||
# 在某些上下文中可能无法获取,此时静默失败
|
||||
logger.warning("No database instance provided for audit logging")
|
||||
return
|
||||
|
||||
audit_repo = AuditRepository(db)
|
||||
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,
|
||||
username=username,
|
||||
project_id=project_id,
|
||||
action=action,
|
||||
resource_type=resource_type,
|
||||
resource_id=resource_id,
|
||||
ip_address=ip_address,
|
||||
user_agent=user_agent,
|
||||
request_method=request_method,
|
||||
request_path=request_path,
|
||||
request_data=request_data,
|
||||
response_status=response_status,
|
||||
error_message=error_message,
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"Audit log created: action={action}, user={username or user_id}, "
|
||||
f"resource={resource_type}:{resource_id}"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
# 审计日志失败不应影响业务流程
|
||||
logger.error(f"Failed to create audit log: {e}", exc_info=True)
|
||||
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:
|
||||
|
||||
@@ -35,10 +35,41 @@ class Settings(BaseSettings):
|
||||
INFLUXDB_ORG: str = "org"
|
||||
INFLUXDB_BUCKET: str = "bucket"
|
||||
|
||||
# Metadata Database Config (PostgreSQL)
|
||||
METADATA_DB_NAME: str = "system_hub"
|
||||
METADATA_DB_HOST: str = "localhost"
|
||||
METADATA_DB_PORT: str = "5432"
|
||||
METADATA_DB_USER: str = "postgres"
|
||||
METADATA_DB_PASSWORD: str = "password"
|
||||
|
||||
METADATA_DB_POOL_SIZE: int = 5
|
||||
METADATA_DB_MAX_OVERFLOW: int = 10
|
||||
|
||||
PROJECT_PG_CACHE_SIZE: int = 50
|
||||
PROJECT_TS_CACHE_SIZE: int = 50
|
||||
PROJECT_PG_POOL_SIZE: int = 5
|
||||
PROJECT_PG_MAX_OVERFLOW: int = 10
|
||||
PROJECT_TS_POOL_MIN_SIZE: int = 1
|
||||
PROJECT_TS_POOL_MAX_SIZE: int = 10
|
||||
|
||||
# Keycloak JWT (optional override)
|
||||
KEYCLOAK_PUBLIC_KEY: str = ""
|
||||
KEYCLOAK_ALGORITHM: str = "RS256"
|
||||
|
||||
# Auth bypass (temporary)
|
||||
AUTH_DISABLED: bool = False
|
||||
|
||||
@property
|
||||
def SQLALCHEMY_DATABASE_URI(self) -> str:
|
||||
return f"postgresql://{self.DB_USER}:{self.DB_PASSWORD}@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}"
|
||||
|
||||
@property
|
||||
def METADATA_DATABASE_URI(self) -> str:
|
||||
return (
|
||||
f"postgresql+psycopg://{self.METADATA_DB_USER}:{self.METADATA_DB_PASSWORD}"
|
||||
f"@{self.METADATA_DB_HOST}:{self.METADATA_DB_PORT}/{self.METADATA_DB_NAME}"
|
||||
)
|
||||
|
||||
class Config:
|
||||
env_file = ".env"
|
||||
extra = "ignore"
|
||||
|
||||
Reference in New Issue
Block a user