initial commit

This commit is contained in:
2025-04-29 18:09:00 +08:00
commit 4faed52de5
690 changed files with 13481 additions and 0 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,90 @@
"""
日志中间件
"""
import json
from django.conf import settings
from django.contrib.auth.models import AnonymousUser
from django.utils.deprecation import MiddlewareMixin
from apps.system.models import OperationLog
from apps.user.models import Users
from utils.log_util.request_util import (
get_browser,
get_os,
get_request_data,
get_request_ip,
get_request_path,
)
class ApiLoggingMiddleware(MiddlewareMixin):
"""
用于记录API访问日志中间件
"""
def __init__(self, get_response=None):
super().__init__(get_response)
self.enable = getattr(settings, 'API_LOG_ENABLE', None) or False
self.methods = getattr(settings, 'API_LOG_METHODS', None) or set()
self.operation_log_id = None
@classmethod
def __handle_request(cls, request):
request.request_ip = get_request_ip(request)
request.request_data = get_request_data(request)
request.request_path = get_request_path(request)
def __handle_response(self, request, response):
# request_data,request_ip由PermissionInterfaceMiddleware中间件中添加的属性
body = getattr(request, 'request_data', {})
# 请求含有password则用*替换掉(暂时先用于所有接口的password请求参数)
if isinstance(body, dict) and body.get('password', ''):
body['password'] = '*' * len(body['password'])
if not hasattr(response, 'data') or not isinstance(response.data, dict):
response.data = {}
try:
if not response.data and response.content:
content = json.loads(response.content.decode())
response.data = content if isinstance(content, dict) else {}
except Exception:
return
if getattr(request, 'user', None) is None:
return
user = request.user
if isinstance(user, AnonymousUser):
return
# 如果操作日志在settings.API_OPERATION_EXCLUDE_START记录的路径中则不操作【暂时不记录因为太多了】
for path in settings.API_OPERATION_EXCLUDE_START:
if request.request_path.startswith(path):
return
info = {
'request_username': user.username if isinstance(user, Users) else user['username'],
'request_ip': getattr(request, 'request_ip', 'unknown'),
'creator_id': user.id if isinstance(user, Users) else user['id'],
'request_method': request.method,
'request_path': request.request_path,
'request_body': body,
'response_code': response.data.get('code'),
'request_os': get_os(request),
'request_browser': get_browser(request),
# 'request_msg': request.session.get('request_msg'),
'status': True if response.data.get('code') in [2000, ] else False,
'json_result': {"code": response.data.get('code'), "msg": response.data.get('result')},
}
operation_log, creat = OperationLog.objects.update_or_create(defaults=info, id=self.operation_log_id)
if not operation_log.request_modular and settings.API_MODEL_MAP.get(request.request_path, None):
operation_log.request_modular = settings.API_MODEL_MAP[request.request_path]
operation_log.save()
def process_request(self, request):
self.__handle_request(request)
def process_response(self, request, response):
"""
主要请求处理完之后记录
:param request:
:param response:
:return:
"""
if self.enable:
if self.methods == 'ALL' or request.method in self.methods:
self.__handle_response(request, response)
return response

View File

@@ -0,0 +1,132 @@
"""
request工具类
"""
import json
from apps.system.models import LoginLog
from django.urls.resolvers import ResolverMatch
from user_agents import parse
def get_request_ip(request):
"""
获取请求IP
:param request:
:return:
"""
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR', '')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[-1].strip()
return ip
ip = request.META.get('REMOTE_ADDR', '') or getattr(request, 'request_ip', None)
return ip or 'unknown'
def get_request_data(request):
"""
获取请求参数
:param request:
:return:
"""
request_data = getattr(request, 'request_data', None)
if request_data:
return request_data
data: dict = {**request.GET.dict(), **request.POST.dict()}
if not data:
try:
body = request.body
if body:
data = json.loads(body)
except Exception as e:
pass
if not isinstance(data, dict):
data = {'data': data}
return data
def get_request_path(request, *args, **kwargs):
"""
获取请求路径
:param request:
:param args:
:param kwargs:
:return:
"""
request_path = getattr(request, 'request_path', None)
if request_path:
return request_path
values = []
for arg in args:
if len(arg) == 0:
continue
if isinstance(arg, str):
values.append(arg)
elif isinstance(arg, (tuple, set, list)):
values.extend(arg)
elif isinstance(arg, dict):
values.extend(arg.values())
if len(values) == 0:
return request.path
path: str = request.path
for value in values:
path = path.replace('/' + value, '/' + '{id}')
return path
def get_request_canonical_path(request, ):
"""
获取请求路径
:param request:
:param args:
:param kwargs:
:return:
"""
request_path = getattr(request, 'request_canonical_path', None)
if request_path:
return request_path
path: str = request.path
resolver_match: ResolverMatch = request.resolver_match
for value in resolver_match.args:
path = path.replace(f"/{value}", "/{id}")
for key, value in resolver_match.kwargs.items():
if key == 'pk':
path = path.replace(f"/{value}", f"/{{id}}")
continue
path = path.replace(f"/{value}", f"/{{{key}}}")
return path
def get_browser(request, ):
"""
获取浏览器名
:param request:
:param args:
:param kwargs:
:return:
"""
ua_string = request.META['HTTP_USER_AGENT']
user_agent = parse(ua_string)
return user_agent.get_browser()
def get_os(request, ):
"""
获取操作系统
:param request:
:param args:
:param kwargs:
:return:
"""
ua_string = request.META['HTTP_USER_AGENT']
user_agent = parse(ua_string)
return user_agent.get_os()
def save_login_log(request, user):
"""
保存登录日志
:return:
"""
ip = get_request_ip(request=request)
analysis_data = {
'username': user.username,
'ip': ip,
'agent': str(parse(request.META['HTTP_USER_AGENT'])),
'browser': get_browser(request),
'os': get_os(request),
'creator_id': user.id
}
LoginLog.objects.create(**analysis_data)