131 lines
4.1 KiB
Python
131 lines
4.1 KiB
Python
|
|
# =============================================================================
|
||
|
|
# 企微IT智能服务台 — 审计日志模型
|
||
|
|
# =============================================================================
|
||
|
|
# 说明: 对应数据库 audit_logs 表,记录所有高危/RBAC 操作 + 登录/MFA 事件
|
||
|
|
# 给 auditor 角色 + admin 提供只读审计能力
|
||
|
|
#
|
||
|
|
# 何时写入:
|
||
|
|
# - 高危操作 (role_change / config_change / data_export / account_disable / account_create_reset)
|
||
|
|
# - RBAC 操作 (assign_role / revoke_role / create_mapping_rule / delete_mapping_rule)
|
||
|
|
# - 登录事件 (qrcode_login / sso_login / password_login)
|
||
|
|
# - MFA 事件 (bind / verify / reset)
|
||
|
|
# - 业务敏感操作 (resolve_conversation / transfer_conversation)
|
||
|
|
# =============================================================================
|
||
|
|
|
||
|
|
import uuid
|
||
|
|
from datetime import datetime
|
||
|
|
from typing import Optional
|
||
|
|
|
||
|
|
from sqlalchemy import JSON, DateTime, Index, String, Text
|
||
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
||
|
|
|
||
|
|
from app.database import Base
|
||
|
|
|
||
|
|
|
||
|
|
class AuditLog(Base):
|
||
|
|
"""审计日志模型 — 对应 audit_logs 表。
|
||
|
|
|
||
|
|
Attributes:
|
||
|
|
id: 日志唯一标识(UUID)
|
||
|
|
employee_id: 操作人(企微 UserID,系统操作填 "system")
|
||
|
|
action: 操作类型(如 "role_change", "login", "mfa_verify")
|
||
|
|
resource: 目标资源类型("agent" / "conversation" / "system_config" 等)
|
||
|
|
resource_id: 目标资源 ID
|
||
|
|
details: 详细上下文(JSON,前后值/IP/UA 等)
|
||
|
|
result: "success" / "failure" / "partial"
|
||
|
|
ip_address: 操作来源 IP(可选)
|
||
|
|
user_agent: 操作来源 UA(可选)
|
||
|
|
created_at: 时间
|
||
|
|
"""
|
||
|
|
|
||
|
|
__tablename__ = "audit_logs"
|
||
|
|
|
||
|
|
# 主键:UUID
|
||
|
|
id: Mapped[str] = mapped_column(
|
||
|
|
String(36),
|
||
|
|
primary_key=True,
|
||
|
|
default=lambda: str(uuid.uuid4()),
|
||
|
|
)
|
||
|
|
|
||
|
|
# 操作人(企微 UserID, 系统操作填 "system")
|
||
|
|
employee_id: Mapped[str] = mapped_column(
|
||
|
|
String(100),
|
||
|
|
nullable=False,
|
||
|
|
comment="操作人(employee_id / 'system')",
|
||
|
|
)
|
||
|
|
|
||
|
|
# 操作类型
|
||
|
|
# 例: "role_change" / "config_change" / "login" / "mfa_verify" /
|
||
|
|
# "qrcode_login" / "sso_login" / "password_login" /
|
||
|
|
# "resolve_conversation" / "transfer_conversation" / "data_export"
|
||
|
|
action: Mapped[str] = mapped_column(
|
||
|
|
String(50),
|
||
|
|
nullable=False,
|
||
|
|
comment="操作类型",
|
||
|
|
)
|
||
|
|
|
||
|
|
# 目标资源类型
|
||
|
|
# 例: "agent" / "conversation" / "system_config" / "role" / "user_role"
|
||
|
|
resource: Mapped[str] = mapped_column(
|
||
|
|
String(50),
|
||
|
|
nullable=False,
|
||
|
|
comment="目标资源类型",
|
||
|
|
)
|
||
|
|
|
||
|
|
# 目标资源 ID(字符串,跨表通用)
|
||
|
|
resource_id: Mapped[Optional[str]] = mapped_column(
|
||
|
|
String(100),
|
||
|
|
nullable=True,
|
||
|
|
comment="目标资源 ID",
|
||
|
|
)
|
||
|
|
|
||
|
|
# 详细上下文(JSON)
|
||
|
|
# 例: {"role": "agent", "reason": "新员工转岗", "ip": "10.80.0.5"}
|
||
|
|
details: Mapped[Optional[dict]] = mapped_column(
|
||
|
|
JSON,
|
||
|
|
nullable=True,
|
||
|
|
comment="详细上下文(JSON)",
|
||
|
|
)
|
||
|
|
|
||
|
|
# 结果
|
||
|
|
# "success" / "failure" / "partial"
|
||
|
|
result: Mapped[str] = mapped_column(
|
||
|
|
String(20),
|
||
|
|
nullable=False,
|
||
|
|
default="success",
|
||
|
|
comment="执行结果",
|
||
|
|
)
|
||
|
|
|
||
|
|
# 来源 IP
|
||
|
|
ip_address: Mapped[Optional[str]] = mapped_column(
|
||
|
|
String(64),
|
||
|
|
nullable=True,
|
||
|
|
comment="来源 IP",
|
||
|
|
)
|
||
|
|
|
||
|
|
# 来源 User-Agent
|
||
|
|
user_agent: Mapped[Optional[str]] = mapped_column(
|
||
|
|
Text,
|
||
|
|
nullable=True,
|
||
|
|
comment="来源 User-Agent",
|
||
|
|
)
|
||
|
|
|
||
|
|
# 时间
|
||
|
|
created_at: Mapped[datetime] = mapped_column(
|
||
|
|
DateTime(timezone=True),
|
||
|
|
nullable=False,
|
||
|
|
default=datetime.now,
|
||
|
|
comment="时间",
|
||
|
|
)
|
||
|
|
|
||
|
|
# 索引:按 employee_id / action / time 查询
|
||
|
|
__table_args__ = (
|
||
|
|
Index("idx_audit_employee_id", "employee_id"),
|
||
|
|
Index("idx_audit_action", "action"),
|
||
|
|
Index("idx_audit_resource", "resource", "resource_id"),
|
||
|
|
Index("idx_audit_created_at", "created_at"),
|
||
|
|
)
|
||
|
|
|
||
|
|
def __repr__(self) -> str:
|
||
|
|
return f"<AuditLog(action={self.action}, employee={self.employee_id}, result={self.result})>"
|