From c514a254c79068bb9d81c25cf4153176603c7bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8C=BF=E5=B0=8F=E5=A4=A9?= <1638245306@qq.com> Date: Fri, 24 Mar 2023 16:06:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=8F=98=E5=8C=96:=20?= =?UTF-8?q?=E5=8A=A0=E5=85=A5=E6=B5=8F=E8=A7=88=E5=99=A8=E5=8D=95=E7=82=B9?= =?UTF-8?q?=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/application/settings.py | 10 ++++++++- backend/dvadmin/system/models.py | 1 + backend/dvadmin/system/views/login.py | 10 ++++++++- backend/dvadmin/utils/exception.py | 11 ++++++++-- web/src/api/service.js | 22 ++++++++----------- .../store/modules/d2admin/modules/account.js | 3 ++- 6 files changed, 39 insertions(+), 18 deletions(-) diff --git a/backend/application/settings.py b/backend/application/settings.py index 61adde3..2974c4e 100644 --- a/backend/application/settings.py +++ b/backend/application/settings.py @@ -54,6 +54,7 @@ INSTALLED_APPS = [ "rest_framework", "django_filters", "corsheaders", # 注册跨域app + 'rest_framework_simplejwt.token_blacklist', "dvadmin.system", "drf_yasg", "captcha", @@ -306,12 +307,14 @@ from datetime import timedelta SIMPLE_JWT = { # token有效时长 - "ACCESS_TOKEN_LIFETIME": timedelta(minutes=120), + "ACCESS_TOKEN_LIFETIME": timedelta(seconds=10), # token刷新后的有效时间 "REFRESH_TOKEN_LIFETIME": timedelta(days=1), # 设置前缀 "AUTH_HEADER_TYPES": ("JWT",), "ROTATE_REFRESH_TOKENS": True, + 'BLACKLIST_AFTER_ROTATION': True, + 'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',), } # ====================================# @@ -387,6 +390,8 @@ SYSTEM_CONFIG = {} # 字典配置 DICTIONARY_CONFIG = {} + + # ================================================= # # ******************** 插件配置 ******************** # # ================================================= # @@ -399,4 +404,7 @@ PLUGINS_URL_PATTERNS = [] # from dvadmin_upgrade_center.settings import * # 升级中心 # from dvadmin_celery.settings import * # celery 异步任务 # ... +from dvadmin_third.settings import * # 扫码登录 +from dvadmin_uniapp.settings import * # uniapp后端 + # ********** 一键导入插件配置结束 ********** diff --git a/backend/dvadmin/system/models.py b/backend/dvadmin/system/models.py index 4a93767..e3c2b84 100644 --- a/backend/dvadmin/system/models.py +++ b/backend/dvadmin/system/models.py @@ -45,6 +45,7 @@ class Users(CoreModel,AbstractUser): blank=True, help_text="关联部门", ) + last_token = models.CharField(max_length=255,null=True,blank=True, verbose_name="最后一次登录Token", help_text="最后一次登录Token") def set_password(self, raw_password): super().set_password(hashlib.md5(raw_password.encode(encoding="UTF-8")).hexdigest()) diff --git a/backend/dvadmin/system/views/login.py b/backend/dvadmin/system/views/login.py index a8fbbae..6ca43c7 100644 --- a/backend/dvadmin/system/views/login.py +++ b/backend/dvadmin/system/views/login.py @@ -12,7 +12,8 @@ from drf_yasg.utils import swagger_auto_schema from rest_framework import serializers from rest_framework.views import APIView from rest_framework_simplejwt.serializers import TokenObtainPairSerializer -from rest_framework_simplejwt.views import TokenObtainPairView +from rest_framework_simplejwt.tokens import RefreshToken, AccessToken +from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView from django.conf import settings @@ -105,6 +106,13 @@ class LoginSerializer(TokenObtainPairSerializer): request.user = self.user # 记录登录日志 save_login_log(request=request) + # 将之前登录用户的token加入黑名单 + last_token = self.user.last_token + if last_token: + token = RefreshToken(last_token) + token.blacklist() + # 将最新的token保存到用户表 + Users.objects.filter(id=self.user.id).update(last_token=data.get('refresh')) return {"code": 2000, "msg": "请求成功", "data": data} diff --git a/backend/dvadmin/utils/exception.py b/backend/dvadmin/utils/exception.py index 83cd3c9..ea45adb 100644 --- a/backend/dvadmin/utils/exception.py +++ b/backend/dvadmin/utils/exception.py @@ -12,6 +12,7 @@ import traceback from django.db.models import ProtectedError from django.http import Http404 from rest_framework.exceptions import APIException as DRFAPIException, AuthenticationFailed +from rest_framework.status import HTTP_407_PROXY_AUTHENTICATION_REQUIRED, HTTP_401_UNAUTHORIZED from rest_framework.views import set_rollback, exception_handler from dvadmin.utils.json_response import ErrorResponse @@ -33,8 +34,14 @@ def CustomExceptionHandler(ex, context): # 调用默认的异常处理函数 response = exception_handler(ex, context) if isinstance(ex, AuthenticationFailed): - code = 401 - msg = ex.detail + if response and response.data.get('detail') =="Given token not valid for any token type": + code = 401 + msg = ex.detail + elif response and response.data.get('detail') =="Token is blacklisted": + return ErrorResponse(status=HTTP_401_UNAUTHORIZED) + else: + code = 401 + msg = ex.detail elif isinstance(ex,Http404): code = 400 msg = "接口地址不正确" diff --git a/web/src/api/service.js b/web/src/api/service.js index e5ab0f8..823c517 100644 --- a/web/src/api/service.js +++ b/web/src/api/service.js @@ -78,12 +78,10 @@ function createService () { // return dataAxios.data return dataAxios case 401: - // TODO 置换token 未完善 - util.cookies.remove('token') - util.cookies.remove('uuid') - util.cookies.remove('refresh') - router.push({ path: '/login' }) - errorCreate(`${getErrorMessage(dataAxios.msg)}`) + refreshTken().then(res => { + util.cookies.set('token', res.access) + router.push({path:'/index'}) + }) break case 404: dataNotFound(`${dataAxios.msg}`) @@ -109,13 +107,11 @@ function createService () { error.message = '请求错误' break case 401: - refreshTken().then(res => { - util.cookies.set('token', res.access) - }).catch(e => { - router.push({ name: 'login' }) - router.go(0) - error.message = '未认证,请登录' - }) + util.cookies.remove('token') + util.cookies.remove('uuid') + util.cookies.remove('refresh') + router.push({ path: '/login' }) + error.message = '系统已检测到您的账号在其他地方登录~' break case 403: error.message = '拒绝访问' diff --git a/web/src/store/modules/d2admin/modules/account.js b/web/src/store/modules/d2admin/modules/account.js index bd87a7c..2f106dc 100644 --- a/web/src/store/modules/d2admin/modules/account.js +++ b/web/src/store/modules/d2admin/modules/account.js @@ -33,7 +33,8 @@ export default { username, password, captcha, - captchaKey + captchaKey, + refresh: util.cookies.get('refresh') || null }) // 设置 cookie 一定要存 uuid 和 token 两个 cookie // 整个系统依赖这两个数据进行校验和存储