system消息通知:修复已读消息bug;permission:接口权限完成。
parent
c9a34da1a5
commit
2514d98173
15
README.md
15
README.md
|
@ -1,6 +1,6 @@
|
||||||
# Django-Vue-Admin
|
# Django-Vue-Admin
|
||||||
|
|
||||||
[](https://gitee.com/liqianglog/django-vue-admin/blob/master/LICENSE) [](https://pypi.org/project/django-simpleui/#history) [](https://python.org/) [](https://nodejs.org/zh-cn/download/releases/)[](https://pypi.org/project/django-simpleui/)
|
[](https://gitee.com/liqianglog/django-vue-admin/blob/master/LICENSE) [](https://pypi.org/project/django-simpleui/#history) [](https://python.org/) 
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,9 +68,6 @@ git clone https://gitee.com/liqianglog/django-vue-admin.git
|
||||||
cd dvadmin-ui
|
cd dvadmin-ui
|
||||||
|
|
||||||
# 安装依赖
|
# 安装依赖
|
||||||
npm install
|
|
||||||
|
|
||||||
# 建议不要直接使用cnpm安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题。
|
|
||||||
npm install --registry=https://registry.npm.taobao.org
|
npm install --registry=https://registry.npm.taobao.org
|
||||||
|
|
||||||
# 启动服务
|
# 启动服务
|
||||||
|
@ -95,7 +92,12 @@ npm run build:prod
|
||||||
~~~bash
|
~~~bash
|
||||||
1. 进入项目目录 cd dvadmin-backend
|
1. 进入项目目录 cd dvadmin-backend
|
||||||
2. 在项目根目录中,复制 ./conf/env.example.py 文件为一份新的到 ./conf 文件夹下,并重命名为 env.py
|
2. 在项目根目录中,复制 ./conf/env.example.py 文件为一份新的到 ./conf 文件夹下,并重命名为 env.py
|
||||||
|
|
||||||
3. 在 env.py 中配置数据库信息
|
3. 在 env.py 中配置数据库信息
|
||||||
|
mysql数据库版本建议:5.7以上
|
||||||
|
mysql数据库字符集:utf8mb4
|
||||||
|
mysql数据库排序规则:utf8mb4_0900_ai_ci
|
||||||
|
|
||||||
4. 安装依赖环境
|
4. 安装依赖环境
|
||||||
pip3 install -r requirements.txt
|
pip3 install -r requirements.txt
|
||||||
5. 执行迁移命令:
|
5. 执行迁移命令:
|
||||||
|
@ -104,10 +106,13 @@ npm run build:prod
|
||||||
6. 初始化数据
|
6. 初始化数据
|
||||||
python3 manage.py init
|
python3 manage.py init
|
||||||
7. 启动项目
|
7. 启动项目
|
||||||
python3 manage.py runserver 0.0.0.0:8000
|
python3 manage.py runserver 127.0.0.1:8000
|
||||||
|
|
||||||
定时任务启动命令:
|
定时任务启动命令:
|
||||||
celery -A application worker -B --loglevel=info
|
celery -A application worker -B --loglevel=info
|
||||||
|
注:
|
||||||
|
Windows 运行celery 需要安装 pip install eventlet
|
||||||
|
celery -A application worker -P eventlet --loglevel=info
|
||||||
|
|
||||||
初始账号:admin 密码:123456
|
初始账号:admin 密码:123456
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ from conf.env import *
|
||||||
|
|
||||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
sys.path.insert(0,os.path.join(BASE_DIR,'apps'))
|
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
|
||||||
# Quick-start development settings - unsuitable for production
|
# Quick-start development settings - unsuitable for production
|
||||||
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ INSTALLED_APPS = [
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
'vadmin.op_drf.middleware.PermissionModeMiddleware', # 权限中间件
|
||||||
'corsheaders.middleware.CorsMiddleware',
|
'corsheaders.middleware.CorsMiddleware',
|
||||||
'django.middleware.security.SecurityMiddleware',
|
'django.middleware.security.SecurityMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
|
@ -202,7 +203,7 @@ LOGGING = {
|
||||||
'loggers': {
|
'loggers': {
|
||||||
# default日志
|
# default日志
|
||||||
'': {
|
'': {
|
||||||
'handlers': ['console','error','file'],
|
'handlers': ['console', 'error', 'file'],
|
||||||
'level': 'INFO',
|
'level': 'INFO',
|
||||||
},
|
},
|
||||||
# 数据库相关日志
|
# 数据库相关日志
|
||||||
|
@ -300,11 +301,11 @@ USERNAME_FIELD = 'username'
|
||||||
# ************** 登录验证码配置 ************** #
|
# ************** 登录验证码配置 ************** #
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
CAPTCHA_STATE = CAPTCHA_STATE
|
CAPTCHA_STATE = CAPTCHA_STATE
|
||||||
#字母验证码
|
# 字母验证码
|
||||||
CAPTCHA_IMAGE_SIZE = (160, 60) # 设置 captcha 图片大小
|
CAPTCHA_IMAGE_SIZE = (160, 60) # 设置 captcha 图片大小
|
||||||
CAPTCHA_LENGTH = 4 # 字符个数
|
CAPTCHA_LENGTH = 4 # 字符个数
|
||||||
CAPTCHA_TIMEOUT = 1 # 超时(minutes)
|
CAPTCHA_TIMEOUT = 1 # 超时(minutes)
|
||||||
#加减乘除验证码
|
# 加减乘除验证码
|
||||||
CAPTCHA_OUTPUT_FORMAT = '%(image)s %(text_field)s %(hidden_field)s '
|
CAPTCHA_OUTPUT_FORMAT = '%(image)s %(text_field)s %(hidden_field)s '
|
||||||
CAPTCHA_FONT_SIZE = 40 # 字体大小
|
CAPTCHA_FONT_SIZE = 40 # 字体大小
|
||||||
CAPTCHA_FOREGROUND_COLOR = '#0033FF' # 前景色
|
CAPTCHA_FOREGROUND_COLOR = '#0033FF' # 前景色
|
||||||
|
@ -312,7 +313,7 @@ CAPTCHA_BACKGROUND_COLOR = '#F5F7F4' # 背景色
|
||||||
CAPTCHA_NOISE_FUNCTIONS = (
|
CAPTCHA_NOISE_FUNCTIONS = (
|
||||||
# 'captcha.helpers.noise_arcs', # 线
|
# 'captcha.helpers.noise_arcs', # 线
|
||||||
# 'captcha.helpers.noise_dots', # 点
|
# 'captcha.helpers.noise_dots', # 点
|
||||||
)
|
)
|
||||||
# CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.random_char_challenge'
|
# CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.random_char_challenge'
|
||||||
CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.math_challenge'
|
CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.math_challenge'
|
||||||
|
|
||||||
|
@ -320,5 +321,10 @@ API_LOG_ENABLE = True
|
||||||
# API_LOG_METHODS = 'ALL' # ['POST', 'DELETE']
|
# API_LOG_METHODS = 'ALL' # ['POST', 'DELETE']
|
||||||
# API_LOG_METHODS = ['POST', 'DELETE'] # ['POST', 'DELETE']
|
# API_LOG_METHODS = ['POST', 'DELETE'] # ['POST', 'DELETE']
|
||||||
BROKER_URL = f'redis://:{REDIS_PASSWORD if REDIS_PASSWORD else ""}@{os.getenv("REDIS_HOST") or REDIS_HOST}:' \
|
BROKER_URL = f'redis://:{REDIS_PASSWORD if REDIS_PASSWORD else ""}@{os.getenv("REDIS_HOST") or REDIS_HOST}:' \
|
||||||
f'{REDIS_PORT}/{locals().get("CELERY_DB",2)}' #Broker使用Redis
|
f'{REDIS_PORT}/{locals().get("CELERY_DB", 2)}' # Broker使用Redis
|
||||||
CELERYBEAT_SCHEDULER = 'django_celery_beat.schedulers.DatabaseScheduler' #Backend数据库
|
CELERYBEAT_SCHEDULER = 'django_celery_beat.schedulers.DatabaseScheduler' # Backend数据库
|
||||||
|
# ================================================= #
|
||||||
|
# ************** 其他配置 ************** #
|
||||||
|
# ================================================= #
|
||||||
|
# 接口权限
|
||||||
|
INTERFACE_PERMISSION = {locals().get("INTERFACE_PERMISSION", False)}
|
||||||
|
|
|
@ -22,7 +22,7 @@ from django.urls import re_path, include
|
||||||
from django.views.static import serve
|
from django.views.static import serve
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
from apps.vadmin.op_drf.response import SuccessResponse
|
from vadmin.utils.response import SuccessResponse
|
||||||
|
|
||||||
|
|
||||||
class CaptchaRefresh(APIView):
|
class CaptchaRefresh(APIView):
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
"""
|
"""
|
||||||
django中间件
|
django中间件
|
||||||
"""
|
"""
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import AnonymousUser
|
from django.contrib.auth.models import AnonymousUser
|
||||||
from django.utils.deprecation import MiddlewareMixin
|
from django.utils.deprecation import MiddlewareMixin
|
||||||
|
|
||||||
|
from apps.vadmin.permission.models import Menu
|
||||||
from apps.vadmin.system.models import OperationLog
|
from apps.vadmin.system.models import OperationLog
|
||||||
from ..utils.request_util import get_request_ip, get_request_data, get_request_path, get_browser, get_os, \
|
from ..utils.request_util import get_request_ip, get_request_data, get_request_path, get_browser, get_os, \
|
||||||
get_login_location
|
get_login_location, get_request_canonical_path, get_request_user
|
||||||
|
from ..utils.response import ErrorJsonResponse
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class ApiLoggingMiddleware(MiddlewareMixin):
|
class ApiLoggingMiddleware(MiddlewareMixin):
|
||||||
|
@ -77,3 +83,78 @@ class PermissionModeMiddleware(MiddlewareMixin):
|
||||||
"""
|
"""
|
||||||
权限模式拦截判断
|
权限模式拦截判断
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def process_request(self, request):
|
||||||
|
"""
|
||||||
|
判断环境变量中,是否为演示模式(正常可忽略此判断)
|
||||||
|
:param request:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
white_list = ['/admin/logout/', '/admin/login/']
|
||||||
|
if os.getenv('DEMO_ENV') and not request.method == 'GET' and request.path not in white_list:
|
||||||
|
return ErrorJsonResponse(data={}, msg=f'演示模式,不允许操作!')
|
||||||
|
|
||||||
|
def has_interface_permission(self, request, method, view_path, user=None):
|
||||||
|
"""
|
||||||
|
接口权限验证,优先级:
|
||||||
|
(1)接口是否接入权限管理, 是:继续; 否:通过
|
||||||
|
(2)认证的user是否superuser, 是:通过; 否:继续
|
||||||
|
(3)user的角色有该接口权限, 是:通过, 否:不通过
|
||||||
|
|
||||||
|
auth_code含义: auth_code >=0, 表示接口认证通过; auth_code < 0, 表示无接口访问权限, 具体含义如下
|
||||||
|
-1:
|
||||||
|
-10: 该请求已认证的用户没有这个接口的访问权限
|
||||||
|
0:
|
||||||
|
1: 白名单
|
||||||
|
10: 该接口没有录入权限系统, 放行 请求中认证的用户为超级管理员, 直接放行
|
||||||
|
20: 请求中认证的用户是superuser放行
|
||||||
|
30: 请求中认证的用户对应的角色中,某个角色包含了该接口的访问权限, 放行
|
||||||
|
1. 先获取所有录入系统的接口
|
||||||
|
2 判断此用户是否为 superuser
|
||||||
|
3. 获取此用户所请求的接口
|
||||||
|
4. 获取此用户关联角色所有有权限的接口
|
||||||
|
|
||||||
|
:param interface: 接口模型
|
||||||
|
:param path: 接口路径
|
||||||
|
:param method: 请求方法
|
||||||
|
:param project: 接口所属项目
|
||||||
|
:param args:
|
||||||
|
:param kwargs:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
interface_dict = Menu.get_interface_dict()
|
||||||
|
# (1) 接口是否接入权限管理, 是:继续; 否:通过
|
||||||
|
if not view_path in interface_dict.get(method, []):
|
||||||
|
return 10
|
||||||
|
# (2)认证的user是否superuser, 是:通过; 否:继续
|
||||||
|
if user.is_superuser or (hasattr(user, 'role') and user.role.filter(status='1', admin=True).count()):
|
||||||
|
return 20
|
||||||
|
# (3)user的角色有该接口权限, 是:通过, 否:不通过
|
||||||
|
if view_path in user.get_user_interface_dict:
|
||||||
|
return 30
|
||||||
|
return -10
|
||||||
|
|
||||||
|
def process_view(self, request, view_func, view_args, view_kwargs):
|
||||||
|
if not settings.INTERFACE_PERMISSION:
|
||||||
|
return
|
||||||
|
user = get_request_user(request)
|
||||||
|
|
||||||
|
if user and not isinstance(user, AnonymousUser):
|
||||||
|
method = request.method.upper()
|
||||||
|
if method == 'GET': # GET 不设置接口权限
|
||||||
|
return
|
||||||
|
view_path = get_request_canonical_path(request, *view_args, **view_kwargs)
|
||||||
|
auth_code = self.has_interface_permission(request, method, view_path, user)
|
||||||
|
logger.info(f"[{user.username}] {method}:{view_path}, 权限认证:{auth_code}")
|
||||||
|
if auth_code >= 0:
|
||||||
|
return
|
||||||
|
return ErrorJsonResponse(data={}, msg=f'无接口访问权限!')
|
||||||
|
|
||||||
|
def process_response(self, request, response):
|
||||||
|
"""
|
||||||
|
主要请求处理完之后记录
|
||||||
|
:param request:
|
||||||
|
:param response:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
return response
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from django.db.models import IntegerField, ForeignKey, CharField, CASCADE
|
from django.core.cache import cache
|
||||||
|
from django.db.models import IntegerField, ForeignKey, CharField, CASCADE, Q
|
||||||
|
|
||||||
from ...op_drf.models import CoreModel
|
from ...op_drf.models import CoreModel
|
||||||
|
|
||||||
|
@ -34,6 +35,31 @@ class Menu(CoreModel):
|
||||||
visible = CharField(max_length=8, verbose_name="显示状态")
|
visible = CharField(max_length=8, verbose_name="显示状态")
|
||||||
isCache = CharField(max_length=8, verbose_name="是否缓存")
|
isCache = CharField(max_length=8, verbose_name="是否缓存")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_interface_dict(cls):
|
||||||
|
"""
|
||||||
|
获取所有接口列表
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
interface_dict = cache.get('permission_interface_dict', {})
|
||||||
|
if not interface_dict:
|
||||||
|
for ele in Menu.objects.filter(~Q(interface_path=''), ~Q(interface_path=None), status='1', ).values(
|
||||||
|
'interface_path', 'interface_method'):
|
||||||
|
if ele.get('interface_method') in interface_dict:
|
||||||
|
interface_dict[ele.get('interface_method', '')].append(ele.get('interface_path'))
|
||||||
|
else:
|
||||||
|
interface_dict[ele.get('interface_method', '')] = [ele.get('interface_path')]
|
||||||
|
cache.set('permission_interface_dict', interface_dict, 84600)
|
||||||
|
return interface_dict
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def delete_cache(cls):
|
||||||
|
"""
|
||||||
|
清空缓存中的接口列表
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
cache.delete('permission_interface_dict')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = '菜单管理'
|
verbose_name = '菜单管理'
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
from django.contrib.auth.models import UserManager, AbstractUser
|
from django.contrib.auth.models import UserManager, AbstractUser
|
||||||
|
from django.core.cache import cache
|
||||||
from django.db.models import IntegerField, ForeignKey, CharField, TextField, ManyToManyField, CASCADE
|
from django.db.models import IntegerField, ForeignKey, CharField, TextField, ManyToManyField, CASCADE
|
||||||
|
|
||||||
from ...op_drf.fields import CreateDateTimeField, UpdateDateTimeField
|
from ...op_drf.fields import CreateDateTimeField, UpdateDateTimeField
|
||||||
|
@ -28,6 +29,29 @@ class UserProfile(AbstractUser):
|
||||||
create_datetime = CreateDateTimeField()
|
create_datetime = CreateDateTimeField()
|
||||||
update_datetime = UpdateDateTimeField()
|
update_datetime = UpdateDateTimeField()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def get_user_interface_dict(self):
|
||||||
|
interface_dict = cache.get(f'permission_interface_dict{self.username}', {})
|
||||||
|
if not interface_dict:
|
||||||
|
for ele in self.role.filter(status='1', menu__status='1').values('menu__interface_path',
|
||||||
|
'menu__interface_method').distinct():
|
||||||
|
interface_path = ele.get('menu__interface_path')
|
||||||
|
if interface_path is None or interface_path == '':
|
||||||
|
continue
|
||||||
|
if ele.get('menu__interface_method') in interface_dict:
|
||||||
|
interface_dict[ele.get('menu__interface_method', '')].append(interface_path)
|
||||||
|
else:
|
||||||
|
interface_dict[ele.get('menu__interface_method', '')] = [interface_path]
|
||||||
|
cache.set(f'permission_interface_dict_{self.username}', interface_dict, 84600)
|
||||||
|
return interface_dict
|
||||||
|
|
||||||
|
@property
|
||||||
|
def delete_cache(self):
|
||||||
|
"""
|
||||||
|
清空缓存中的接口列表
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
return cache.delete(f'permission_interface_dict_{self.username}')
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = '用户管理'
|
verbose_name = '用户管理'
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
|
|
|
@ -87,11 +87,9 @@ class CommonPermission(CustomPermission):
|
||||||
return int(instance.dept_belong_id) in list(set(dept_list))
|
return int(instance.dept_belong_id) in list(set(dept_list))
|
||||||
|
|
||||||
def has_permission(self, request: Request, view: APIView):
|
def has_permission(self, request: Request, view: APIView):
|
||||||
"""判断是否为演示模式"""
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def has_object_permission(self, request: Request, view: APIView, instance):
|
def has_object_permission(self, request: Request, view: APIView, instance):
|
||||||
self.message = f"没有此数据操作权限!"
|
self.message = f"没有此数据操作权限!"
|
||||||
res = self.check_queryset(request, instance)
|
res = self.check_queryset(request, instance)
|
||||||
print(res)
|
|
||||||
return res
|
return res
|
||||||
|
|
|
@ -37,6 +37,10 @@ class MenuCreateUpdateSerializer(CustomModelSerializer):
|
||||||
# raise APIException(message=f'仅Manger能创建/更新角色为公共角色')
|
# raise APIException(message=f'仅Manger能创建/更新角色为公共角色')
|
||||||
return super().validate(attrs)
|
return super().validate(attrs)
|
||||||
|
|
||||||
|
def save(self, **kwargs):
|
||||||
|
Menu.delete_cache()
|
||||||
|
return super().save(**kwargs)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Menu
|
model = Menu
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
@ -91,7 +95,7 @@ class DeptTreeSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Dept
|
model = Dept
|
||||||
fields = ('id', 'label', 'parentId','status')
|
fields = ('id', 'label', 'parentId', 'status')
|
||||||
|
|
||||||
|
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
|
|
|
@ -25,6 +25,7 @@ class GetUserProfileView(APIView):
|
||||||
user_dict = UserProfileSerializer(request.user).data
|
user_dict = UserProfileSerializer(request.user).data
|
||||||
permissions_list = ['*:*:*'] if user_dict.get('admin') else Menu.objects.filter(
|
permissions_list = ['*:*:*'] if user_dict.get('admin') else Menu.objects.filter(
|
||||||
role__userprofile=request.user).values_list('perms', flat=True)
|
role__userprofile=request.user).values_list('perms', flat=True)
|
||||||
|
delete_cache = request.user.delete_cache
|
||||||
return SuccessResponse({
|
return SuccessResponse({
|
||||||
'permissions': [ele for ele in permissions_list if ele],
|
'permissions': [ele for ele in permissions_list if ele],
|
||||||
'roles': Role.objects.filter(userprofile=request.user).values_list('roleKey', flat=True),
|
'roles': Role.objects.filter(userprofile=request.user).values_list('roleKey', flat=True),
|
||||||
|
|
|
@ -22,9 +22,9 @@ from django.urls import re_path, include
|
||||||
from rest_framework.documentation import include_docs_urls
|
from rest_framework.documentation import include_docs_urls
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
from .op_drf.response import SuccessResponse
|
|
||||||
from .permission.views import GetUserProfileView, GetRouters
|
from .permission.views import GetUserProfileView, GetRouters
|
||||||
from .utils.login import LoginView, LogoutView
|
from .utils.login import LoginView, LogoutView
|
||||||
|
from .utils.response import SuccessResponse
|
||||||
|
|
||||||
|
|
||||||
class CaptchaRefresh(APIView):
|
class CaptchaRefresh(APIView):
|
||||||
|
|
|
@ -8,10 +8,10 @@ from django.contrib.auth.models import AbstractBaseUser
|
||||||
from django.contrib.auth.models import AnonymousUser
|
from django.contrib.auth.models import AnonymousUser
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.urls.resolvers import ResolverMatch
|
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
|
from user_agents import parse
|
||||||
|
|
||||||
|
from apps.vadmin.utils.authentication import OpAuthJwtAuthentication
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,18 +26,8 @@ def get_request_user(request, authenticate=True):
|
||||||
user: AbstractBaseUser = getattr(request, 'user', None)
|
user: AbstractBaseUser = getattr(request, 'user', None)
|
||||||
if user and user.is_authenticated:
|
if user and user.is_authenticated:
|
||||||
return user
|
return user
|
||||||
authentication: BaseAuthentication = None
|
user, tokrn = OpAuthJwtAuthentication().authenticate(request)
|
||||||
for authentication_class in drf_settings.DEFAULT_AUTHENTICATION_CLASSES:
|
print(22, user)
|
||||||
try:
|
|
||||||
authentication = authentication_class()
|
|
||||||
user_auth_tuple = authentication.authenticate(request)
|
|
||||||
if user_auth_tuple is not None:
|
|
||||||
user, token = user_auth_tuple
|
|
||||||
if authenticate:
|
|
||||||
request.user = user
|
|
||||||
return user
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
return user or AnonymousUser()
|
return user or AnonymousUser()
|
||||||
|
|
||||||
|
|
||||||
|
@ -127,9 +117,11 @@ def get_request_canonical_path(request, *args, **kwargs):
|
||||||
for value in resolver_match.args:
|
for value in resolver_match.args:
|
||||||
path = path.replace(f"/{value}", "/{id}")
|
path = path.replace(f"/{value}", "/{id}")
|
||||||
for key, value in resolver_match.kwargs.items():
|
for key, value in resolver_match.kwargs.items():
|
||||||
path = path.replace(f"/{value}", f"/{{{key}}}")
|
|
||||||
if key == 'pk':
|
if key == 'pk':
|
||||||
pass
|
path = path.replace(f"/{value}", f"/{{id}}")
|
||||||
|
continue
|
||||||
|
path = path.replace(f"/{value}", f"/{{{key}}}")
|
||||||
|
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""
|
"""
|
||||||
常用的Response以及Django的Response、DRF的Response
|
常用的Response以及Django的Response、DRF的Response
|
||||||
"""
|
"""
|
||||||
from django.http.response import DjangoJSONEncoder
|
from django.http.response import DjangoJSONEncoder, JsonResponse
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
|
|
||||||
|
@ -56,3 +56,36 @@ class ErrorResponse(Response):
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.std_data)
|
return str(self.std_data)
|
||||||
|
|
||||||
|
|
||||||
|
class SuccessJsonResponse(JsonResponse):
|
||||||
|
"""
|
||||||
|
标准JsonResponse, SuccessJsonResponse(data)SuccessJsonResponse(data=data)
|
||||||
|
(1)仅SuccessResponse无法使用时才能推荐使用SuccessJsonResponse
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, data, msg='success', encoder=DjangoJSONEncoder, safe=True, json_dumps_params=None, **kwargs):
|
||||||
|
std_data = {
|
||||||
|
"code": 200,
|
||||||
|
"data": data,
|
||||||
|
"msg": msg,
|
||||||
|
"status": 'success'
|
||||||
|
}
|
||||||
|
super().__init__(std_data, encoder, safe, json_dumps_params, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class ErrorJsonResponse(JsonResponse):
|
||||||
|
"""
|
||||||
|
标准JsonResponse, 仅ErrorResponse无法使用时才能使用ErrorJsonResponse
|
||||||
|
(1)默认错误码返回2001, 也可以指定其他返回码:ErrorJsonResponse(code=xxx)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, data, msg='error', code=201, encoder=OpDRFJSONEncoder, safe=True, json_dumps_params=None,
|
||||||
|
**kwargs):
|
||||||
|
std_data = {
|
||||||
|
"code": code,
|
||||||
|
"data": data,
|
||||||
|
"msg": msg,
|
||||||
|
"status": 'error'
|
||||||
|
}
|
||||||
|
super().__init__(std_data, encoder, safe, json_dumps_params, **kwargs)
|
||||||
|
|
|
@ -39,3 +39,5 @@ CAPTCHA_STATE = True
|
||||||
# 操作日志配置
|
# 操作日志配置
|
||||||
API_LOG_ENABLE = True
|
API_LOG_ENABLE = True
|
||||||
API_LOG_METHODS = ['POST', 'DELETE', 'PUT'] # 'ALL' or ['POST', 'DELETE']
|
API_LOG_METHODS = ['POST', 'DELETE', 'PUT'] # 'ALL' or ['POST', 'DELETE']
|
||||||
|
# 接口权限
|
||||||
|
INTERFACE_PERMISSION = True
|
||||||
|
|
|
@ -39,9 +39,9 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getToken } from "@/utils/auth";
|
import {getToken} from "@/utils/auth";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
// 值
|
// 值
|
||||||
value: [String, Object, Array],
|
value: [String, Object, Array],
|
||||||
|
@ -135,8 +135,12 @@ export default {
|
||||||
},
|
},
|
||||||
// 上传成功回调
|
// 上传成功回调
|
||||||
handleUploadSuccess(res, file) {
|
handleUploadSuccess(res, file) {
|
||||||
|
if (res.code === 200) {
|
||||||
this.$message.success("上传成功");
|
this.$message.success("上传成功");
|
||||||
this.$emit("input", res.url);
|
this.$emit("input", res.data.file);
|
||||||
|
} else {
|
||||||
|
this.$message.error(res.msg);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// 删除文件
|
// 删除文件
|
||||||
handleDelete(index) {
|
handleDelete(index) {
|
||||||
|
|
Loading…
Reference in New Issue