drf認證、許可權、頻率、過濾、排序、異常處理
阿新 • • 發佈:2020-11-07
認證元件
使用方法:
1、新建一個認證類檔案,繼承BaseAuthentication
from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed from rest_framework.response import Response from app03 import models class Bookauth(BaseAuthentication): def authenticate(self, request): token=request.META.get('HTTP_TOKEN') if token: token_obj=models.UserToken.objects.filter(token=token).first() if token_obj: return token_obj.user,token else: raise AuthenticationFailed('驗證失敗') else: raise AuthenticationFailed('請求頭沒有token資訊')
2、認證類區域性配置
''' 區域性使用,在列表內發那個值認證類 區域性禁用,設定列表為空 ''' class Login(APIView): #區域性使用 authentication_classes = [Bookauth,] #區域性禁用 # authentication_classes = [] def post(self, request): user = models.User.objects.filter(username=request.data.get('username'), password=request.data.get('password')).first() if user: token = uuid.uuid4() models.UserToken.objects.update_or_create(user=user, defaults={'token': token}) return Response("{'msg':'登陸成功'}") else: return Response("{'msg':'使用者不存在'}")
3、全域性配置,在settings檔案中配置:
REST_FRAMEWORK={ # "DEFAULT_AUTHENTICATION_CLASSES":["app04.MyAuth.Login_auth",] "DEFAULT_AUTHENTICATION_CLASSES":["app03.BookAuth.Bookauth",] }
認證原始碼分析:
#1 APIVIew----》dispatch方法---》self.initial(request, *args, **kwargs)---->有認證,許可權,頻率 #2 只讀認證原始碼: self.perform_authentication(request) #3 self.perform_authentication(request)就一句話:request.user,需要去drf的Request物件中找user屬性(方法) #4 Request類中的user方法,剛開始來,沒有_user,走 self._authenticate() #5 核心,就是Request類的 _authenticate(self): def _authenticate(self): # 遍歷拿到一個個認證器,進行認證 # self.authenticators配置的一堆認證類產生的認證類物件組成的 list #self.authenticators 你在檢視類中配置的一個個的認證類:authentication_classes=[認證類1,認證類2],物件的列表 for authenticator in self.authenticators: try: # 認證器(物件)呼叫認證方法authenticate(認證類物件self, request請求物件) # 返回值:登陸的使用者與認證的資訊組成的 tuple # 該方法被try包裹,代表該方法會拋異常,拋異常就代表認證失敗 user_auth_tuple = authenticator.authenticate(self) #注意這self是request物件 except exceptions.APIException: self._not_authenticated() raise # 返回值的處理 if user_auth_tuple is not None: self._authenticator = authenticator # 如何有返回值,就將 登陸使用者 與 登陸認證 分別儲存到 request.user、request.auth self.user, self.auth = user_auth_tuple return # 如果返回值user_auth_tuple為空,代表認證通過,但是沒有 登陸使用者 與 登陸認證資訊,代表遊客 self._not_authenticated()
許可權
# APIView---->dispatch---->initial--->self.check_permissions(request)(APIView的物件方法) def check_permissions(self, request): # 遍歷許可權物件列表得到一個個許可權物件(許可權器),進行許可權認證 for permission in self.get_permissions(): # 許可權類一定有一個has_permission許可權方法,用來做許可權認證的 # 引數:許可權物件self、請求物件request、檢視類物件 # 返回值:有許可權返回True,無許可權返回False if not permission.has_permission(request, self): self.permission_denied( request, message=getattr(permission, 'message', None) )許可權原始碼分析
使用方法:
(1)自定義一個許可權類,繼承BasePermission類,程式碼如下:
from rest_framework.permissions import BasePermission class User_per(BasePermission): def has_permission(self, request, view): user=request.user is_staff=user.is_staff if is_staff==1: #1:管理員 2:普通使用者 3:匿名使用者 return True else: return False
(2)全域性配置跟區域性配置:
REST_FRAMEWORK = { # 許可權全域性配置 "DEFAULT_PERMISSION_CLASSES": ['app01.app_per.User_per', ] } #區域性配置 class TestView1(APIView): #區域性禁用 permission_classes = [] #區域性配置 permission_classes = [User_per] def get(self,request): return Response('我是匿名使用者')
內建許可權:
from rest_framework.permissions import IsAdminUser from rest_framework.authentication import SessionAuthentication class Supper(APIView): permission_classes = [IsAdminUser] authentication_classes = [SessionAuthentication] def get(self,request): return Response('這是超級管理員的測試')
頻率
全域性配置:settings檔案下
REST_FRAMEWORK = { #限制 'DEFAULT_THROTTLE_CLASSES': ( 'rest_framework.throttling.AnonRateThrottle',#未登入使用者 'rest_framework.throttling.UserRateThrottle',#登陸使用者 ), 'DEFAULT_THROTTLE_RATES': { 'anon': '3/m', #1分鐘訪問3次,m後面無論帶什麼都沒影響,因為它只擷取m 'user': '5/m' }, }
區域性配置:
from rest_framework.throttling import UserRateThrottle class TestView1(APIView): #頻率區域性配置 throttle_classes = [UserRateThrottle] def get(self,request): return Response('我是匿名使用者')
過濾
使用方法:
1、安裝:pipinstall django-filter
2、在settings中進行app註冊:
INSTALLED_APPS = [ 'django.contrib.admin', ....'django_filters', ]
3、全域性配置:
REST_FRAMEWORK = { #過濾全域性配置 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',), }
4、區域性配置以及在檢視類的使用
from django_filters.rest_framework import DjangoFilterBackend class BookView(ModelViewSet): queryset = models.Book.objects.all() serializer_class = Book_ser #區域性配置 filter_backends = [DjangoFilterBackend] #配置要過濾的欄位 filter_fields = ('name','price',)
排序
1、匯入OrderingFilter模組
from rest_framework.filters import OrderingFilter
2、在檢視類上的使用:
class BookView(ModelViewSet): authentication_classes = [] permission_classes = [] throttle_classes = [] queryset = models.Book.objects.all() serializer_class = Book_ser #區域性配置 # filter_backends = [DjangoFilterBackend] # #配置要過濾的欄位 # filter_fields = ('name','price',) filter_backends = [OrderingFilter] ordering_fields = ('id', 'price') ''' 使用 -號:表示降序 ''' http://127.0.0.1:8000/books2/?ordering=-price http://127.0.0.1:8000/books2/?ordering=price
異常處理
1、自定義一個異常處理方法,用來重寫rest_framework.views中exception_handler方法:
from rest_framework.views import exception_handler from rest_framework.response import Response from rest_framework import status def my_exception_handler(exc, context): response=exception_handler(exc, context) # 返回兩種情況,一個是None,drf沒有處理 #一個是response物件,django處理了,處理格式不是很好 if not response: if isinstance(exc, ZeroDivisionError): return Response(data={'status': 9999, 'msg': "除以0的錯誤" + str(exc)}, status=status.HTTP_400_BAD_REQUEST) return Response(data={'status':1111,'msg':str(exc)},status=status.HTTP_400_BAD_REQUEST) else: return Response(data={'status':2222,'msg':response.data.get('detail')},status=status.HTTP_400_BAD_REQUEST)
全域性配置:
REST_FRAMEWORK = { #異常 'EXCEPTION_HANDLER': 'app01.wsigi.APIhandle_exceptn'#自己寫的異常處理方法 }