diff --git a/dvadmin-backend/apps/vadmin/system/models/__init__.py b/dvadmin-backend/apps/vadmin/system/models/__init__.py index 38e4a36..c51517a 100644 --- a/dvadmin-backend/apps/vadmin/system/models/__init__.py +++ b/dvadmin-backend/apps/vadmin/system/models/__init__.py @@ -5,4 +5,5 @@ from ..models.web_set import WebSet from ..models.save_file import SaveFile from ..models.message_push import MessagePush from ..models.message_push import MessagePushUser +from ..models.logininfor import LoginInfor diff --git a/dvadmin-backend/apps/vadmin/system/models/logininfor.py b/dvadmin-backend/apps/vadmin/system/models/logininfor.py new file mode 100644 index 0000000..1c78331 --- /dev/null +++ b/dvadmin-backend/apps/vadmin/system/models/logininfor.py @@ -0,0 +1,19 @@ +from django.db.models import CharField, BooleanField + +from ...op_drf.models import CoreModel + + +class LoginInfor(CoreModel): + browser = CharField(max_length=64, verbose_name="浏览器") + ipaddr = CharField(max_length=32, verbose_name="ip地址", null=True, blank=True) + loginLocation = CharField(max_length=64, verbose_name="登录位置", null=True, blank=True) + msg = CharField(max_length=64, verbose_name="操作信息", null=True, blank=True) + os = CharField(max_length=64, verbose_name="操作系统", null=True, blank=True) + status = BooleanField(default=False, verbose_name="登录状态") + + class Meta: + verbose_name = '登录日志' + verbose_name_plural = verbose_name + + def __str__(self): + return f"{self.creator and self.creator.name}" diff --git a/dvadmin-backend/apps/vadmin/system/models/operlog.py b/dvadmin-backend/apps/vadmin/system/models/operlog.py new file mode 100644 index 0000000..34a55f5 --- /dev/null +++ b/dvadmin-backend/apps/vadmin/system/models/operlog.py @@ -0,0 +1,19 @@ +from django.db.models import TextField, CharField + +from ...op_drf.models import CoreModel + + +class WebSet(CoreModel): + name = CharField(max_length=64, verbose_name="站点名称") + web_site = CharField(max_length=256, verbose_name="站点网址", null=True, blank=True) + logo = CharField(max_length=256, verbose_name="网站Logo", null=True, blank=True) + record_info = TextField(verbose_name="备案信息", null=True, blank=True) + statistics_code = TextField(verbose_name="统计代码", null=True, blank=True) + copyright_info = TextField(verbose_name="版权信息", null=True, blank=True) + + class Meta: + verbose_name = '操作日志' + verbose_name_plural = verbose_name + + def __str__(self): + return f"{self.name}" diff --git a/dvadmin-backend/apps/vadmin/utils/login.py b/dvadmin-backend/apps/vadmin/utils/login.py index 81bfd11..2336355 100644 --- a/dvadmin-backend/apps/vadmin/utils/login.py +++ b/dvadmin-backend/apps/vadmin/utils/login.py @@ -12,9 +12,10 @@ from rest_framework_jwt.views import ObtainJSONWebToken, jwt_response_payload_ha from .exceptions import GenException from .jwt_util import jwt_get_session_id +from .request_util import get_request_ip, get_os, get_browser, get_login_location from .response import SuccessResponse, ErrorResponse - # from .jwt_util import jwt_response_payload_handler +from ..system.models.logininfor import LoginInfor logger = logging.getLogger(__name__) @@ -61,6 +62,18 @@ class LoginView(ObtainJSONWebToken): else: raise GenException(message='验证码错误') + def save_login_infor(self, request, msg='',status=True): + User = get_user_model() + instance = LoginInfor() + instance.browser = get_browser(request) + instance.ipaddr = get_request_ip(request) + instance.loginLocation = get_login_location(request) + instance.msg = msg + instance.os = get_os(request) + instance.status = status + instance.creator = request.user and User.objects.filter(username=request.data.get('username')).first() + instance.save() + def post(self, request, *args, **kwargs): # 校验验证码 self.jarge_captcha(request) @@ -75,6 +88,7 @@ class LoginView(ObtainJSONWebToken): session_id = jwt_get_session_id(token) key = f"{self.prefix}_{session_id}_{username}" cache.set(key, token, self.ex.total_seconds()) + self.save_login_infor(request, '登录成功') if self.JWT_AUTH_COOKIE and token: expiration = (datetime.datetime.utcnow() + self.ex) response.set_cookie(self.JWT_AUTH_COOKIE, @@ -83,8 +97,9 @@ class LoginView(ObtainJSONWebToken): domain=settings.SESSION_COOKIE_DOMAIN, httponly=False) return response + self.save_login_infor(request, '登录失败,账户/密码不正确',False) return ErrorResponse(data=serializer.errors, msg='账户/密码不正确') - def handle_exception(self, exc): - print(exc) - return ErrorResponse(data=None, msg=exc.message) + # def handle_exception(self, exc): + # print(exc) + # return ErrorResponse(data=None, msg=exc.message) diff --git a/dvadmin-backend/apps/vadmin/utils/request_util.py b/dvadmin-backend/apps/vadmin/utils/request_util.py index 47b3b8e..eb46195 100644 --- a/dvadmin-backend/apps/vadmin/utils/request_util.py +++ b/dvadmin-backend/apps/vadmin/utils/request_util.py @@ -3,12 +3,13 @@ Request工具类 """ import json import logging + from django.contrib.auth.models import AbstractBaseUser -from rest_framework.authentication import BaseAuthentication -from rest_framework.settings import api_settings as drf_settings from django.contrib.auth.models import AnonymousUser from django.urls.resolvers import ResolverMatch - +from rest_framework.authentication import BaseAuthentication +from rest_framework.settings import api_settings as drf_settings +from user_agents import parse logger = logging.getLogger(__name__) @@ -126,3 +127,48 @@ def get_request_canonical_path(request, *args, **kwargs): if key == 'pk': pass return path + + +def get_browser(request, *args, **kwargs): + """ + 获取浏览器名 + :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, *args, **kwargs): + """ + 获取操作系统 + :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 get_login_location(request, *args, **kwargs): + """ + 获取ip 登录位置 + :param request: + :param args: + :param kwargs: + :return: + """ + import requests + import eventlet # 导入eventlet这个模块 + eventlet.monkey_patch(thread=False) # 必须加这条代码 + with eventlet.Timeout(2, False): # 设置超时时间为2秒 + apiurl = "http://whois.pconline.com.cn/ip.jsp?ip=%s" % get_request_ip(request) + r = requests.get(apiurl) + content = r.content.decode('GBK') + return content.replace('\r', '').replace('\n', '') + return "" diff --git a/dvadmin-backend/requirements.txt b/dvadmin-backend/requirements.txt index 7a7a9d4..953c6e4 100644 --- a/dvadmin-backend/requirements.txt +++ b/dvadmin-backend/requirements.txt @@ -21,3 +21,5 @@ six==1.15.0 sqlparse==0.4.1 xlwt==1.3.0 coreapi==2.3.3 +user-agents==2.2.0 +eventlet==0.30.2