權限控制
前言
用戶驗證用戶權限,根據不同訪問權限控制對不同內容的訪問。
建議了解視圖、token驗證的內容。
使用流程
- 自定義訪問權限類,繼承
BasePermission,重寫has_permission()方法,如果權限通過,就返回True,不通過就返回False。has_permission()方法接受兩個參數,分別是request和view,也就是視圖類的實例化本身。

- 配置。
局部配置:
permission_classes = [MyUserPermission]
全局配置:
REST_FRAMEWORK={
'DEFAULT_PERMISSION_CLASSES': ['libs.MyAuth.UserPermission',],
}
示例
class SVIPPermission(BasePermission): # 推薦繼承BasePermission類
# message = 'You do not have permission to perform this action.'#默認值
message = '無此權限!!!'
def has_permission(self, request, view):
if request.user.user_type == 3:
return False # False為沒權限
# view.queryset = # 可以使用這種方式控制視圖中要處理的數據(根據不同權限)
return True # True為有權限
源碼分析
進入dispatch函數,查看initial方法(執行三大驗證)中的check_permissions方法:

self.check_permissions(request)將會根據request中的用戶內容進行權限控制。



由上可知,permission_classes要么讀取配置文件中的DEFAULT_PERMISSION_CLASSES(全局),要么就在視圖類中直接對permission_classes賦值(局部)。
節流限制
前言
控制網站訪問頻率。
使用流程
- 自定義限制類,繼承
BaseThrottle。 - 指定從配置文件中要讀取的scope(key),形式為
scope="key"
全局配置:
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle'
],
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day',
'user': '1000/day'
}
}
局部配置:
throttle_classes = [UserRateThrottle]
就比如UserRateThrottle,繼承了SimpleRateThrottle,指定了它所限制的scope,重寫了get_cache_key方法。

源碼分析
在APIView的initial方法中,三大驗證還剩下最后一個沒有分析,那就是訪問頻率驗證,如下圖:

接下來讓我們查看check_throttles,可以看到,驗證訪問頻率的時候,調用的方法為頻率驗證類的allow_request方法。

其中get_throttles用的還是老套路:

示例
自定義一個頻率限制類:
from rest_framework.throttling import BaseThrottle
import time
# 存放訪問記錄(一般放數據庫或者緩存中)
VISIT_RECORD = {}
class VisitThrottle(BaseThrottle):
def __init__(self):
self.history = None
def allow_request(self, request, view):
# 1. 獲取用戶ip
remote_addr = request.META.get("REMOTE_ADDR")
# 2. 添加到訪問記錄中
ctime = time.time()
# 當VISIT_RECORD中沒有這個記錄,可以直接訪問,添加一個記錄
if remote_addr not in VISIT_RECORD:
VISIT_RECORD[remote_addr] = [ctime, ]
return True
history = VISIT_RECORD.get(remote_addr)
self.history = history
# 拿到最后歷史記錄里面的最后一個時間,如果最后一個時間小於當前時間-60(一分鍾之前的記錄)
while history and history[-1] < ctime - 60:
history.pop()
if len(history) < 3: # 允許
history.insert(0, ctime)
return True
return False # False表示訪問頻率太高被限制
def wait(self):
"""
還需要等多少秒可以訪問
:return:
"""
ctime = time.time()
return 60 - (ctime - self.history[-1])
注意:官方內置的 SimpleRateThrottle 類中對scope的處理值得一看。
