settings配置
REST_FRAMEWORK = {
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
# 配置默认页面大小
'PAGE_SIZE': 10,
# 配置默认的分页类
'DEFAULT_PAGINATION_CLASS': 'backstage.helps.MyPageNumberPagination',
# 配置异常处理器
# 'EXCEPTION_HANDLER': 'api.exceptions.exception_handler',
'EXCEPTION_HANDLER': 'backstage.utils.exception_handler', # 替换为自定义的路径
# 配置默认解析器
# 'DEFAULT_PARSER_CLASSES': (
# 'rest_framework.parsers.JSONParser',
# 'rest_framework.parsers.FormParser',
# 'rest_framework.parsers.MultiPartParser',
# ),
# 配置默认限流类
# 'DEFAULT_THROTTLE_CLASSES': (),
# 配置默认授权类
# 'DEFAULT_PERMISSION_CLASSES': (
# 'rest_framework.permissions.IsAuthenticated',
# ),
}
重写异常
import datetime
import jwt
from jwt import InvalidTokenError
from redis import RedisError
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from django_filters import filterset
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed, APIException
from backstage.models import Data, BackstageUser
from express import settings
import threading
from express.settings import SECRET_KEY
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework import status
from django.db import DatabaseError
class BaseAuthException(Exception):
'''自定义权限异常'''
def __init__(self, msg):
self.msg = msg
super().__init__(self, msg)
def __str__(self):
return str(self.msg)
def __call__(self, *args, **kwargs):
return str(self.msg)
def exception_handler(exc, context):
"""
自定义异常处理
:param exc: 别的地方抛的异常就会传给exc
:param context: 字典形式。抛出异常的上下文(即抛出异常的出处;即抛出异常的视图)
:return: Response响应对象
"""
# 调用drf框架原生的异常处理方法,把异常和异常出处交给他处理,如果是序列化器异常就直接处理,处理之后就直接返回
response = drf_exception_handler(exc, context)
print('222', response)
print('111', exc)
# 如果响应为空表示不是序列化器异常,补充数据库异常 和 认证异常
if response is None:
if isinstance(exc, DatabaseError) or isinstance(exc, RedisError):
# 数据库异常
response = Response({'msg': '服务器内部错误'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)
elif isinstance(exc, BaseAuthException):
response = Response({'code': 500, 'msg': '无效的令牌或令牌已过期,请重新登录'})
# --- 未捕获则直接报错
return response
class LoginRequiredAuthentication(BaseAuthentication):
"""登录认证"""
# 如果用户身份验证成功需要返回一个二元组(user, token)
def authenticate(self, request):
token = request.META.get('HTTP_TOKEN')
if token:
try:
print('进入权限认证')
payload = jwt.decode(token, SECRET_KEY)
user = BackstageUser()
print(f'解析参数-->{payload}')
user.userid = payload['userid']
user.is_authenticated = True
return user, token
except InvalidTokenError:
raise BaseAuthException('请提供用户身份令牌')
raise AuthenticationFailed('请提供用户身份令牌')
class SingletonType(type):
'''多线程(元类单例)'''
_instance_lock = threading.Lock()
def __call__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
with SingletonType._instance_lock:
if not hasattr(cls, "_instance"):
cls._instance = super(SingletonType, cls).__call__(*args, **kwargs)
return cls._instance
views中
class UserView(BaseModelViewSet):
'''用户信息crud'''
queryset = User.objects.all().order_by('-user_id')
serializer_class = UserSimpleSerializer
authentication_classes = (LoginRequiredAuthentication,)
....