""" 审计日志 API 路由: - GET /audit/logs - 查询审计日志(管理员) """ from flask import Blueprint, request, jsonify import logging logger = logging.getLogger(__name__) from auth.gateway import require_gateway_auth from data.db import get_connection from core.status_codes import SUCCESS, INTERNAL_ERROR from api.response_utils import success_response, error_response audit_bp = Blueprint('audit', __name__) @audit_bp.route('/audit/logs', methods=['GET']) @require_gateway_auth def get_audit_logs(): """ 查询审计日志 参数: - limit: 返回条数(默认50) - days: 查询天数(默认7) - action: 操作类型过滤(可选) 返回: { "logs": [ { "id": 1, "user_id": "admin001", "username": "admin", "action": "rag_query", "query": "xxx", "result_summary": "...", "role": "admin", "department": "管理部", "ip_address": "127.0.0.1", "duration_ms": 1234, "timestamp": "2025-01-01 12:00:00" } ], "total": 100 } """ limit = request.args.get('limit', 50, type=int) days = request.args.get('days', 7, type=int) action_filter = request.args.get('action', '') try: with get_connection("session") as conn: # 构建查询 where_clauses = ["created_at >= datetime('now', ?)"] params = [f'-{days} days'] if action_filter: where_clauses.append("action = ?") params.append(action_filter) where_sql = " AND ".join(where_clauses) # 查询总数 count_sql = f"SELECT COUNT(*) FROM audit_logs WHERE {where_sql}" total = conn.execute(count_sql, params).fetchone()[0] # 查询日志 query_sql = f""" SELECT id, user_id, username, action, query, result_summary, role, department, ip_address, duration_ms, created_at FROM audit_logs WHERE {where_sql} ORDER BY created_at DESC LIMIT ? """ params.append(limit) rows = conn.execute(query_sql, params).fetchall() logs = [] for row in rows: logs.append({ "id": row[0], "user_id": row[1], "username": row[2], "action": row[3], "query": row[4], "result_summary": row[5], "role": row[6], "department": row[7], "ip_address": row[8], "duration_ms": row[9], "timestamp": row[10] }) return success_response(data={"logs": logs, "total": total}) except Exception as e: logger.error(f"审计查询异常: {e}") return error_response("QUERY_FAILED", INTERNAL_ERROR, "查询失败", http_status=500) def log_audit_event(user_id: str, username: str, action: str, query: str = None, result_summary: str = None, role: str = None, department: str = None, ip_address: str = None, duration_ms: int = None): """ 记录审计日志(供其他模块调用) Args: user_id: 用户ID username: 用户名 action: 操作类型(rag_query, chat, feedback, sync 等) query: 查询内容 result_summary: 结果摘要 role: 用户角色 department: 部门 ip_address: IP地址 duration_ms: 耗时(毫秒) """ try: with get_connection("session") as conn: conn.execute(""" INSERT INTO audit_logs (user_id, username, action, query, result_summary, role, department, ip_address, duration_ms) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) """, (user_id, username, action, query, result_summary, role, department, ip_address, duration_ms)) except Exception as e: # 审计日志写入失败不应影响主流程 logger.debug(f"审计日志写入失败: {e}") pass