From faeee1b92c7eff746c7cd47efaeea1c1858c3f08 Mon Sep 17 00:00:00 2001 From: shaohuzhang1 <80892890+shaohuzhang1@users.noreply.github.com> Date: Wed, 4 Jun 2025 14:23:10 +0800 Subject: [PATCH] feat: log management (#3189) --- apps/common/log/log.py | 99 +++++++++++++++++++++ apps/maxkb/conf.py | 1 - apps/system_manage/migrations/0004_log.py | 33 +++++++ apps/system_manage/models/__init__.py | 1 + apps/system_manage/models/log_management.py | 38 ++++++++ 5 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 apps/common/log/log.py create mode 100644 apps/system_manage/migrations/0004_log.py create mode 100644 apps/system_manage/models/log_management.py diff --git a/apps/common/log/log.py b/apps/common/log/log.py new file mode 100644 index 000000000..0c4f5466d --- /dev/null +++ b/apps/common/log/log.py @@ -0,0 +1,99 @@ +# coding=utf-8 +""" + @project: MaxKB + @Author:虎虎 + @file: log.py + @date:2025/6/4 14:13 + @desc: +""" + +from system_manage.models.log_management import Log + + +def _get_ip_address(request): + """ + 获取ip地址 + @param request: + @return: + """ + x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') + if x_forwarded_for: + ip = x_forwarded_for.split(',')[0] + else: + ip = request.META.get('REMOTE_ADDR') + return ip + + +def _get_user(request): + """ + 获取用户 + @param request: + @return: + """ + user = request.user + if user is None: + return { + + } + return { + "id": str(user.id), + "email": user.email, + "phone": user.phone, + "nick_name": user.nick_name, + "username": user.username, + "role": user.role, + } + + +def _get_details(request): + path = request.path + body = request.data + query = request.query_params + return { + 'path': path, + 'body': body, + 'query': query + } + + +def log(menu: str, operate, get_user=_get_user, get_ip_address=_get_ip_address, get_details=_get_details, + get_operation_object=None): + """ + 记录审计日志 + @param menu: 操作菜单 str + @param operate: 操作 str|func 如果是一个函数 入参将是一个request 响应为str def operate(request): return "操作菜单" + @param get_user: 获取用户 + @param get_ip_address:获取IP地址 + @param get_details: 获取执行详情 + @param get_operation_object: 获取操作对象 + @return: + """ + + def inner(func): + def run(view, request, **kwargs): + status = 200 + operation_object = {} + try: + if get_operation_object is not None: + operation_object = get_operation_object(request, kwargs) + except Exception as e: + pass + try: + return func(view, request, **kwargs) + except Exception as e: + status = 500 + raise e + finally: + ip = get_ip_address(request) + user = get_user(request) + details = get_details(request) + _operate = operate + if callable(operate): + _operate = operate(request) + # 插入审计日志 + Log(menu=menu, operate=_operate, user=user, status=status, ip_address=ip, details=details, + operation_object=operation_object).save() + + return run + + return inner diff --git a/apps/maxkb/conf.py b/apps/maxkb/conf.py index 6abff9788..cb2f28295 100644 --- a/apps/maxkb/conf.py +++ b/apps/maxkb/conf.py @@ -61,7 +61,6 @@ class Config(dict): } } - @staticmethod def get_cache_setting(self): return { 'default': { diff --git a/apps/system_manage/migrations/0004_log.py b/apps/system_manage/migrations/0004_log.py new file mode 100644 index 000000000..376286648 --- /dev/null +++ b/apps/system_manage/migrations/0004_log.py @@ -0,0 +1,33 @@ +# Generated by Django 5.2 on 2025-06-04 06:17 + +import common.encoder.encoder +import uuid +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('system_manage', '0003_workspaceuserresourcepermission_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='Log', + fields=[ + ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, verbose_name='修改时间')), + ('id', models.UUIDField(default=uuid.uuid1, editable=False, primary_key=True, serialize=False, verbose_name='主键id')), + ('menu', models.CharField(max_length=128, verbose_name='操作菜单')), + ('operate', models.CharField(max_length=128, verbose_name='操作')), + ('operation_object', models.JSONField(default=dict, encoder=common.encoder.encoder.SystemEncoder, verbose_name='操作对象')), + ('user', models.JSONField(default=dict, verbose_name='用户信息')), + ('status', models.IntegerField(verbose_name='状态')), + ('ip_address', models.CharField(max_length=128, verbose_name='ip地址')), + ('details', models.JSONField(default=dict, encoder=common.encoder.encoder.SystemEncoder, verbose_name='详情')), + ], + options={ + 'db_table': 'log', + }, + ), + ] diff --git a/apps/system_manage/models/__init__.py b/apps/system_manage/models/__init__.py index eca60db8c..acd03f67e 100644 --- a/apps/system_manage/models/__init__.py +++ b/apps/system_manage/models/__init__.py @@ -8,3 +8,4 @@ """ from .workspace_user_permission import * from .system_setting import * +from .log_management import * diff --git a/apps/system_manage/models/log_management.py b/apps/system_manage/models/log_management.py new file mode 100644 index 000000000..d7d987cf5 --- /dev/null +++ b/apps/system_manage/models/log_management.py @@ -0,0 +1,38 @@ +# coding=utf-8 +""" + @project: MaxKB + @Author:虎虎 + @file: log_management.py + @date:2025/6/4 14:15 + @desc: +""" +import uuid + +from django.db import models + +from common.encoder.encoder import SystemEncoder +from common.mixins.app_model_mixin import AppModelMixin + + +class Log(AppModelMixin): + """ + 审计日志 + """ + id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid1, editable=False, verbose_name="主键id") + + menu = models.CharField(max_length=128, verbose_name="操作菜单") + + operate = models.CharField(max_length=128, verbose_name="操作") + + operation_object = models.JSONField(verbose_name="操作对象", default=dict, encoder=SystemEncoder) + + user = models.JSONField(verbose_name="用户信息", default=dict) + + status = models.IntegerField(verbose_name="状态") + + ip_address = models.CharField(max_length=128, verbose_name="ip地址") + + details = models.JSONField(verbose_name="详情", default=dict, encoder=SystemEncoder) + + class Meta: + db_table = "log"