initial commit
This commit is contained in:
BIN
utils/log_util/__pycache__/middleware.cpython-313.pyc
Normal file
BIN
utils/log_util/__pycache__/middleware.cpython-313.pyc
Normal file
Binary file not shown.
BIN
utils/log_util/__pycache__/middleware.cpython-38.pyc
Normal file
BIN
utils/log_util/__pycache__/middleware.cpython-38.pyc
Normal file
Binary file not shown.
BIN
utils/log_util/__pycache__/request_util.cpython-313.pyc
Normal file
BIN
utils/log_util/__pycache__/request_util.cpython-313.pyc
Normal file
Binary file not shown.
BIN
utils/log_util/__pycache__/request_util.cpython-38.pyc
Normal file
BIN
utils/log_util/__pycache__/request_util.cpython-38.pyc
Normal file
Binary file not shown.
90
utils/log_util/middleware.py
Normal file
90
utils/log_util/middleware.py
Normal 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
|
||||
132
utils/log_util/request_util.py
Normal file
132
utils/log_util/request_util.py
Normal 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)
|
||||
Reference in New Issue
Block a user