權限控制
前言
用戶驗證用戶權限,根據不同訪問權限控制對不同內容的訪問。
建議了解視圖、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
的處理值得一看。