1. 程式人生 > 實用技巧 >Django-DRF認證,許可權,限頻,過濾,排序

Django-DRF認證,許可權,限頻,過濾,排序

一、DRF自定義認證使用

# 1 定義一個類,繼承BaseAuthentication,重寫authenticate方法
class LoginAuth(BaseAuthentication):
    def authenticate(self, request):
        token = request.GET.get('token')
        res = models.UserToken.objects.filter(token=token).first()
        if res:
            return 元組  
        # 返回空或者元組,若返回元組則必須有兩個值,第一個為self.request,第二個self.auth,self是request物件
        else:
            raise AuthenticationFailed('您沒有登入')

            
# 2 使用位置
-區域性使用:在檢視類中配置
authentication_classes = [MyAuthen.LoginAuth, ]  # 是個列表,可以寫多個認證類,其中一個有返回值則不會執行後面
-區域性禁用:在檢視類中配置空
authentication_classes = []
-全域性使用:在settings中使用
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": ["app01.MyAuthen.LoginAuth", ]
}
   
    
# 3 注意:
	1 認證類,認證通過可以返回一個元組,有兩個值,第一個值會給,request.user,第二個值會個request.auth
    2 認證類可以配置多個,按照從前向後的順序執行,如果前面有返回值,認證就不再繼續往下走了

二、DRF自定義許可權使用

許可權的校驗在認證之後,所以可以拿到前面return的request.user和request.auth

# 1 使用寫一個類繼承BasePermission,重寫has_permission

# 假設某個檢視中,超級使用者為1,可以訪問,除了超級使用者以外,都不能訪問
class SuperPermission(BasePermission):
    # 若要列印中文錯誤資訊可以在類中寫message
    # message='錯誤資訊提示'
    def has_permission(self, request, view):
        if request.user.user_type == '1':  # 此處使用了request.user需要認證裡返回來,若不返回就拿不到
            return True
        else:
            return False

        
# 2 使用位置
-區域性使用
permission_classes = [MyAuthen.SuperPermission,]
-區域性禁用
permission_classes = []
-全域性使用
REST_FRAMEWORK = {
    "DEFAULT_PERMISSION_CLASSES": ["app01.MyAuthen.SuperPermission", ]
}

三、DRF自定義限率使用

1.自己寫一個,根據ip限制訪問頻率

# 根據ip進行頻率限制,每分鐘只能訪問3次,邏輯如下
'''
(1)取出訪問者ip
(2)判斷當前ip不在訪問字典裡,新增進去,並且直接返回True,表示第一次訪問,在字典裡,繼續往下走
(3)迴圈判斷當前ip的列表,有值,並且當前時間減去列表的最後一個時間大於60s,把這種資料pop掉,這樣列表中只有60s以內的訪問時間,
(4)判斷,當列表小於3,說明一分鐘以內訪問不足三次,把當前時間插入到列表第一個位置,返回True,順利通過
(5)當大於等於3,說明一分鐘內訪問超過三次,返回False驗證失敗
'''

from rest_framework.throttling import BaseThrottle

class MyThrottle(BaseThrottle):
    VISIT_RECORD = {}  # 存使用者訪問資訊的大字典
    def __init__(self):
        self.history = None
    def allow_request(self,request,view):
        # (1)取出訪問者ip
        ip = request.META.get('REMOTE_ADDR')
        import time
        ctime = time.time()
        # (2)判斷當前ip不在訪問字典裡,新增進去,並且直接返回True,表示第一次訪問
        if ip not in self.VISIT_RECORD:
            self.VISIT_RECORD[ip] = [ctime, ]
            return True
        self.history = self.VISIT_RECORD.get(ip)
        # (3)迴圈判斷當前ip的列表,有值,並且當前時間減去列表的最後一個時間大於60s,把這種資料pop掉,這樣列表中只有60s以內的訪問時間,
        while self.history and ctime - self.history[-1] > 60:
            self.history.pop()
        # (4)判斷,當列表小於3,說明一分鐘以內訪問不足三次,把當前時間插入到列表第一個位置,返回True,順利通過
        # (5)當大於等於3,說明一分鐘內訪問超過三次,返回False驗證失敗
        if len(self.history) < 3:
            self.history.insert(0, ctime)
            return True
        else:
            return False

    def wait(self):
        # 還剩多長時間能訪問
        import time
        ctime = time.time()
        return 60 - (ctime - self.history[-1])

2.自定義限制頻率的步驟

下面的SimpleRateThrottle已經幫我們實現了根據ip限制訪問頻率

# 1 寫一個類,繼承SimpleRateThrottle
class MySimpleThrottle(SimpleRateThrottle):
    scope = 'xxx'
    def get_cache_key(self, request, view):
        #什麼都不寫,就預設以ip限制
        return self.get_ident(request)
    
-setting.py中配置
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_RATES' : {
        'xxx':'10/m'
        '''
        key跟scope對應,value是一個時間,表示每分鐘十次,可以自己改,底層是用/分割,
        然後取右邊第一個索引,所以寫'10/mcbiaba'或'10/m'沒區別
        '''
    }
}


# 2 使用位置
-區域性使用
throttle_classes = [auth.MyThrottle,]
-區域性禁用
throttle_classes = []
-全域性使用
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES':['app01.auth.MyThrottle',],
}

3.其他內建限制頻率類與使用

# 內建頻率類
BaseThrottle:基類
AnonRateThrottle:限制匿名使用者的訪問次數
SimpleRateThrottle:一般用來繼承他,然後我們自定義
ScopedRateThrottle
UserRateThrottle:限制登入使用者訪問次數
    
    
# 其它內建頻率類的使用
AnonRateThrottle:限制匿名使用者的訪問次數,根據ip限制

-區域性使用
throttle_classes = [throttling.AnonRateThrottle]
-全域性使用
-setting.py中配置
'DEFAULT_THROTTLE_RATES' : {
    'anon':'1/m'
}
    

UserRateThrottle:限制登入使用者訪問次數
-限制登入使用者訪問次數UserRateThrottle(根據使用者id限制)

-區域性使用
throttle_classes = [throttling.UserRateThrottle]
-全域性使用
-setting.py中配置
'DEFAULT_THROTTLE_RATES' : {
    'user':'1/m'
}

四、DRF過濾與排序使用

對於查詢的結果,一般我們還需要經過一些過濾或者排序。

DRF自己有內建的過濾功能,我們也可以使用第三方庫,django-filter來過濾,也可以自己寫自定義的過濾方法。

# 1 內建篩選的使用
-在檢視類中配置
filter_backends =[SearchFilter,]
search_fields=('name',) # 表模型中的欄位
-查詢的地址
http://127.0.0.1:8000/students/?search=e  # 模糊查詢
                
# 2 第三方擴充套件的過濾功能
-pip3 install django-filter  :最新版本(2.4.0)要跟django2.2以上搭配
-在檢視類中配置
filter_backends =[DjangoFilterBackend,]
filter_fields=['name','age']
-查詢的時候
http://127.0.0.1:8000/students/?name=lqz&age=18  # 精確查詢
                
                
# 3 自定義:
# 寫一個類MyFilter,繼承BaseFilterBackend
from rest_framework.filters import BaseFilterBackend

# 重寫filter_queryset方法,在該方法內部進行過濾(自己設定的過濾條件)並返回queryset
class MyFilter(BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        # 自己的過濾
        return queryset

# 配置在檢視類中
	filter_backends = [MyFilter,]