功能变化: 加入浏览器单点登录

v2.x
猿小天 2023-03-24 16:06:04 +08:00
parent 69d8c3efc0
commit c514a254c7
6 changed files with 39 additions and 18 deletions

View File

@ -54,6 +54,7 @@ INSTALLED_APPS = [
"rest_framework", "rest_framework",
"django_filters", "django_filters",
"corsheaders", # 注册跨域app "corsheaders", # 注册跨域app
'rest_framework_simplejwt.token_blacklist',
"dvadmin.system", "dvadmin.system",
"drf_yasg", "drf_yasg",
"captcha", "captcha",
@ -306,12 +307,14 @@ from datetime import timedelta
SIMPLE_JWT = { SIMPLE_JWT = {
# token有效时长 # token有效时长
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=120), "ACCESS_TOKEN_LIFETIME": timedelta(seconds=10),
# token刷新后的有效时间 # token刷新后的有效时间
"REFRESH_TOKEN_LIFETIME": timedelta(days=1), "REFRESH_TOKEN_LIFETIME": timedelta(days=1),
# 设置前缀 # 设置前缀
"AUTH_HEADER_TYPES": ("JWT",), "AUTH_HEADER_TYPES": ("JWT",),
"ROTATE_REFRESH_TOKENS": True, "ROTATE_REFRESH_TOKENS": True,
'BLACKLIST_AFTER_ROTATION': True,
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
} }
# ====================================# # ====================================#
@ -387,6 +390,8 @@ SYSTEM_CONFIG = {}
# 字典配置 # 字典配置
DICTIONARY_CONFIG = {} DICTIONARY_CONFIG = {}
# ================================================= # # ================================================= #
# ******************** 插件配置 ******************** # # ******************** 插件配置 ******************** #
# ================================================= # # ================================================= #
@ -399,4 +404,7 @@ PLUGINS_URL_PATTERNS = []
# from dvadmin_upgrade_center.settings import * # 升级中心 # from dvadmin_upgrade_center.settings import * # 升级中心
# from dvadmin_celery.settings import * # celery 异步任务 # from dvadmin_celery.settings import * # celery 异步任务
# ... # ...
from dvadmin_third.settings import * # 扫码登录
from dvadmin_uniapp.settings import * # uniapp后端
# ********** 一键导入插件配置结束 ********** # ********** 一键导入插件配置结束 **********

View File

@ -45,6 +45,7 @@ class Users(CoreModel,AbstractUser):
blank=True, blank=True,
help_text="关联部门", 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): def set_password(self, raw_password):
super().set_password(hashlib.md5(raw_password.encode(encoding="UTF-8")).hexdigest()) super().set_password(hashlib.md5(raw_password.encode(encoding="UTF-8")).hexdigest())

View File

@ -12,7 +12,8 @@ from drf_yasg.utils import swagger_auto_schema
from rest_framework import serializers from rest_framework import serializers
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer 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 from django.conf import settings
@ -105,6 +106,13 @@ class LoginSerializer(TokenObtainPairSerializer):
request.user = self.user request.user = self.user
# 记录登录日志 # 记录登录日志
save_login_log(request=request) 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} return {"code": 2000, "msg": "请求成功", "data": data}

View File

@ -12,6 +12,7 @@ import traceback
from django.db.models import ProtectedError from django.db.models import ProtectedError
from django.http import Http404 from django.http import Http404
from rest_framework.exceptions import APIException as DRFAPIException, AuthenticationFailed 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 rest_framework.views import set_rollback, exception_handler
from dvadmin.utils.json_response import ErrorResponse from dvadmin.utils.json_response import ErrorResponse
@ -33,6 +34,12 @@ def CustomExceptionHandler(ex, context):
# 调用默认的异常处理函数 # 调用默认的异常处理函数
response = exception_handler(ex, context) response = exception_handler(ex, context)
if isinstance(ex, AuthenticationFailed): if isinstance(ex, AuthenticationFailed):
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 code = 401
msg = ex.detail msg = ex.detail
elif isinstance(ex,Http404): elif isinstance(ex,Http404):

View File

@ -78,12 +78,10 @@ function createService () {
// return dataAxios.data // return dataAxios.data
return dataAxios return dataAxios
case 401: case 401:
// TODO 置换token 未完善 refreshTken().then(res => {
util.cookies.remove('token') util.cookies.set('token', res.access)
util.cookies.remove('uuid') router.push({path:'/index'})
util.cookies.remove('refresh') })
router.push({ path: '/login' })
errorCreate(`${getErrorMessage(dataAxios.msg)}`)
break break
case 404: case 404:
dataNotFound(`${dataAxios.msg}`) dataNotFound(`${dataAxios.msg}`)
@ -109,13 +107,11 @@ function createService () {
error.message = '请求错误' error.message = '请求错误'
break break
case 401: case 401:
refreshTken().then(res => { util.cookies.remove('token')
util.cookies.set('token', res.access) util.cookies.remove('uuid')
}).catch(e => { util.cookies.remove('refresh')
router.push({ name: 'login' }) router.push({ path: '/login' })
router.go(0) error.message = '系统已检测到您的账号在其他地方登录~'
error.message = '未认证,请登录'
})
break break
case 403: case 403:
error.message = '拒绝访问' error.message = '拒绝访问'

View File

@ -33,7 +33,8 @@ export default {
username, username,
password, password,
captcha, captcha,
captchaKey captchaKey,
refresh: util.cookies.get('refresh') || null
}) })
// 设置 cookie 一定要存 uuid token 两个 cookie // 设置 cookie 一定要存 uuid token 两个 cookie
// 整个系统依赖这两个数据进行校验和存储 // 整个系统依赖这两个数据进行校验和存储