Skip to content

Commit b8dea89

Browse files
committed
feat: Audit Log
1 parent f6e089d commit b8dea89

File tree

4 files changed

+153
-0
lines changed

4 files changed

+153
-0
lines changed

apps/application/views/application_views.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from common.constants.permission_constants import CompareConstants, PermissionConstants, Permission, Group, Operate, \
2525
ViewPermission, RoleConstants
2626
from common.exception.app_exception import AppAuthenticationFailed
27+
from common.log.log import log
2728
from common.response import result
2829
from common.swagger_api.common_api import CommonApi
2930
from common.util.common import query_params_to_single_dict
@@ -603,6 +604,7 @@ class Page(APIView):
603604
responses=result.get_page_api_response(ApplicationApi.get_response_body_api()),
604605
tags=[_('Application')])
605606
@has_permissions(PermissionConstants.APPLICATION_READ, compare=CompareConstants.AND)
607+
@log(menu=_('Application'), operate=_("Get the application list by page"))
606608
def get(self, request: Request, current_page: int, page_size: int):
607609
return result.success(
608610
ApplicationSerializer.Query(

apps/common/log/log.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# coding=utf-8
2+
"""
3+
@project: MaxKB
4+
@Author:虎
5+
@file: log.py
6+
@date:2025/3/14 16:09
7+
@desc:
8+
"""
9+
10+
from setting.models.log_management import Log
11+
12+
13+
def _get_ip_address(request):
14+
"""
15+
获取ip地址
16+
@param request:
17+
@return:
18+
"""
19+
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
20+
if x_forwarded_for:
21+
ip = x_forwarded_for.split(',')[0]
22+
else:
23+
ip = request.META.get('REMOTE_ADDR')
24+
return ip
25+
26+
27+
def _get_user(request):
28+
"""
29+
获取用户
30+
@param request:
31+
@return:
32+
"""
33+
user = request.user
34+
return {
35+
"id": str(user.id),
36+
"email": user.email,
37+
"phone": user.phone,
38+
"nick_name": user.nick_name,
39+
"username": user.username,
40+
"role": user.role,
41+
}
42+
43+
44+
def _get_details(request):
45+
path = request.path
46+
body = request.data
47+
query = request.query_params
48+
return {
49+
'path': path,
50+
'body': body,
51+
'query': query
52+
}
53+
54+
55+
def log(menu: str, operate, get_user=_get_user, get_ip_address=_get_ip_address, get_details=_get_details):
56+
"""
57+
记录审计日志
58+
@param menu: 操作菜单 str
59+
@param operate: 操作 str|func 如果是一个函数 入参将是一个request 响应为str def operate(request): return "操作菜单"
60+
@param get_user: 获取用户
61+
@param get_ip_address:获取IP地址
62+
@param get_details: 获取执行详情
63+
@return:
64+
"""
65+
66+
def inner(func):
67+
def run(view, request, **kwargs):
68+
status = 200
69+
try:
70+
return func(view, request, **kwargs)
71+
except Exception as e:
72+
status = 500
73+
finally:
74+
ip = get_ip_address(request)
75+
user = get_user(request)
76+
details = get_details(request)
77+
_operate = operate
78+
if callable(operate):
79+
_operate = operate(request)
80+
# 插入审计日志
81+
Log(menu=menu, operate=_operate, user=user, status=status, ip_address=ip, details=details).save()
82+
83+
return run
84+
85+
return inner
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Generated by Django 4.2.18 on 2025-03-17 02:50
2+
3+
from django.db import migrations, models
4+
import uuid
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('setting', '0009_set_default_model_params_form'),
11+
]
12+
13+
operations = [
14+
migrations.CreateModel(
15+
name='Log',
16+
fields=[
17+
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
18+
('update_time', models.DateTimeField(auto_now=True, verbose_name='修改时间')),
19+
('id', models.UUIDField(default=uuid.uuid1, editable=False, primary_key=True, serialize=False, verbose_name='主键id')),
20+
('menu', models.CharField(max_length=128, verbose_name='操作菜单')),
21+
('operate', models.CharField(max_length=128, verbose_name='操作')),
22+
('user', models.JSONField(default=dict, verbose_name='用户信息')),
23+
('status', models.IntegerField(max_length=20, verbose_name='状态')),
24+
('ip_address', models.CharField(max_length=128, verbose_name='ip地址')),
25+
('details', models.JSONField(default=dict, verbose_name='详情')),
26+
],
27+
options={
28+
'db_table': 'log',
29+
},
30+
),
31+
]
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# coding=utf-8
2+
"""
3+
@project: MaxKB
4+
@Author:虎
5+
@file: log_management.py
6+
@date:2025/3/17 9:54
7+
@desc:
8+
"""
9+
import uuid
10+
11+
from django.db import models
12+
13+
from common.mixins.app_model_mixin import AppModelMixin
14+
15+
16+
class Log(AppModelMixin):
17+
"""
18+
审计日志
19+
"""
20+
id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid1, editable=False, verbose_name="主键id")
21+
22+
menu = models.CharField(max_length=128, verbose_name="操作菜单")
23+
24+
operate = models.CharField(max_length=128, verbose_name="操作")
25+
26+
user = models.JSONField(verbose_name="用户信息", default=dict)
27+
28+
status = models.IntegerField(max_length=20, verbose_name="状态")
29+
30+
ip_address = models.CharField(max_length=128, verbose_name="ip地址")
31+
32+
details = models.JSONField(verbose_name="详情", default=dict)
33+
34+
class Meta:
35+
db_table = "log"

0 commit comments

Comments
 (0)