From 505b17263312df3b6d085a4dc806fabb8511ab7d Mon Sep 17 00:00:00 2001 From: xie7654 <765462425@qq.com> Date: Sat, 5 Jul 2025 11:06:21 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=8E=B7=E5=8F=96=E7=9C=9F?= =?UTF-8?q?=E5=AE=9Eip?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 38 +++++++++---------- backend/system/views/user.py | 9 ++++- backend/utils/ip_utils.py | 73 ++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 22 deletions(-) create mode 100644 backend/utils/ip_utils.py diff --git a/README.md b/README.md index d2b8ac3..2cc758e 100644 --- a/README.md +++ b/README.md @@ -13,26 +13,24 @@ ## 功能截图 -### 部门管理 -![部门管理](images/dj_dept.png) - -### 用户管理 -![用户管理](images/dj_user.png) - -### 角色管理 -![角色管理](images/dj_role.png) - -### 岗位管理 -![岗位管理](images/dj_post.png) - -### 菜单管理 -![菜单管理](images/dj_menu.png) - -### 前端界面 -![前端界面](images/dj_vue1.png) - -### 普通员工界面 -![普通员工界面](images/dj_chenze.png) + + + + + + + + + + + + + + + + + +
部门管理
部门管理
用户管理
用户管理
角色管理
角色管理
岗位管理
岗位管理
菜单管理
菜单管理
前端界面
前端界面
权限员工界面
普通员工界面
# 许可证 diff --git a/backend/system/views/user.py b/backend/system/views/user.py index 2167b6b..2b0abde 100644 --- a/backend/system/views/user.py +++ b/backend/system/views/user.py @@ -9,6 +9,7 @@ from rest_framework.permissions import IsAuthenticated from django_filters import rest_framework as filters from system.models import User, Menu, LoginLog, Dept +from utils.ip_utils import get_client_ip from utils.serializers import CustomModelSerializer from utils.custom_model_viewSet import CustomModelViewSet @@ -54,8 +55,12 @@ class UserLogin(ObtainAuthToken): serializer.is_valid(raise_exception=True) user = serializer.validated_data['user'] token, created = Token.objects.get_or_create(user=user) + + # 获取真实IP地址 + client_ip = get_client_ip(request) + # 更新登录IP和登录时间 - user.login_ip = request.META.get('REMOTE_ADDR') + user.login_ip = client_ip user.last_login = timezone.now() user.save(update_fields=['login_ip', 'last_login']) user_data = UserSerializer(user).data @@ -63,7 +68,7 @@ class UserLogin(ObtainAuthToken): LoginLog.objects.create( username=user.username, result=LoginLog.LoginResult.SUCCESS, - user_ip=request.META.get('REMOTE_ADDR', ''), + user_ip=client_ip, user_agent=request.META.get('HTTP_USER_AGENT', '') ) # 在序列化后的数据中加入 accessToken diff --git a/backend/utils/ip_utils.py b/backend/utils/ip_utils.py new file mode 100644 index 0000000..642b157 --- /dev/null +++ b/backend/utils/ip_utils.py @@ -0,0 +1,73 @@ +def get_client_ip(request): + """ + 获取客户端真实IP地址 + 考虑代理服务器的情况,按优先级获取IP + """ + # 按优先级顺序检查各种IP头 + ip_headers = [ + 'HTTP_X_FORWARDED_FOR', # 最常用的代理IP头 + 'HTTP_X_REAL_IP', # Nginx 代理 + 'HTTP_X_CLIENT_IP', # 客户端IP + 'HTTP_X_FORWARDED', # 转发IP + 'HTTP_FORWARDED_FOR', # 标准转发IP + 'HTTP_FORWARDED', # 标准转发 + 'HTTP_CLIENT_IP', # 客户端IP + 'REMOTE_ADDR', # 直接连接IP + ] + + for header in ip_headers: + ip = request.META.get(header) + if ip: + # 处理多个IP的情况(如 X-Forwarded-For: client, proxy1, proxy2) + if ',' in ip: + # 取第一个IP(客户端真实IP) + ip = ip.split(',')[0].strip() + + # 验证IP格式 + if is_valid_ip(ip): + return ip + + # 如果都没有找到,返回 REMOTE_ADDR + return request.META.get('REMOTE_ADDR', '') + + +def is_valid_ip(ip): + """ + 验证IP地址格式是否有效 + """ + if not ip: + return False + + # 简单的IP格式验证 + parts = ip.split('.') + if len(parts) != 4: + return False + + try: + for part in parts: + if not 0 <= int(part) <= 255: + return False + return True + except (ValueError, TypeError): + return False + + +def get_client_ip_simple(request): + """ + 简化版获取客户端IP(推荐用于大多数情况) + """ + # 优先获取 X-Forwarded-For + x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') + if x_forwarded_for: + # 取第一个IP + ip = x_forwarded_for.split(',')[0].strip() + if ip: + return ip + + # 获取 X-Real-IP + x_real_ip = request.META.get('HTTP_X_REAL_IP') + if x_real_ip: + return x_real_ip + + # 最后使用 REMOTE_ADDR + return request.META.get('REMOTE_ADDR', '') \ No newline at end of file