DRF之訪問許可權控制和訪問頻率控制(節流)
阿新 • • 發佈:2021-01-06
# 許可權控制
## 前言
**使用者驗證使用者許可權,根據不同訪問許可權控制對不同內容的訪問。**
建議瞭解檢視、token驗證的內容。
## 使用流程
1. 自定義訪問許可權類,繼承`BasePermission`,重寫`has_permission()`方法,如果許可權通過,就返回`True`,不通過就返回`False`。`has_permission()`方法接受兩個引數,分別是`request`和`view`,也就是檢視類的例項化本身。
![image-20210106113656701](https://img2020.cnblogs.com/blog/2056368/202101/2056368-20210106113657150-1816818317.png)
2. 配置。
區域性配置:
```python
permission_classes = [MyUserPermission]
```
全域性配置:
```python
REST_FRAMEWORK={
'DEFAULT_PERMISSION_CLASSES': ['libs.MyAuth.UserPermission',],
}
```
## 示例
```python
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`方法:
![image-20201230163053258](https://img2020.cnblogs.com/blog/2056368/202012/2056368-20201230163053884-1093386257.png)
`self.check_permissions(request)`將會根據`request`中的使用者內容進行許可權控制。
![image-20201230163450342](https://img2020.cnblogs.com/blog/2056368/202012/2056368-20201230163450875-1494222285.png)
![image-20201230163538055](https://img2020.cnblogs.com/blog/2056368/202012/2056368-20201230163538522-8789747.png)
![image-20210106113841241](https://img2020.cnblogs.com/blog/2056368/202101/2056368-20210106113841738-889803283.png)
由上可知,`permission_classes`要麼讀取配置檔案中的`DEFAULT_PERMISSION_CLASSES`(全域性),要麼就在檢視類中直接對`permission_classes`賦值(區域性)。
# 節流限制
## 前言
**控制網站訪問頻率。**
## 使用流程
1. 自定義限制類,繼承`BaseThrottle`。
2. 指定從配置檔案中要讀取的scope(key),形式為`scope="key"`
全域性配置:
```python
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle'
],
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day',
'user': '1000/day'
}
}
```
區域性配置:
```python
throttle_classes = [UserRateThrottle]
```
就比如`UserRateThrottle`,繼承了`SimpleRateThrottle`,指定了它所限制的`scope`,重寫了`get_cache_key`方法。
![image-20210106115349546](https://img2020.cnblogs.com/blog/2056368/202101/2056368-20210106115349989-1102939528.png)
## 原始碼分析
在`APIView`的`initial`方法中,三大驗證還剩下最後一個沒有分析,那就是訪問頻率驗證,如下圖:
![image-20210106115306589](https://img2020.cnblogs.com/blog/2056368/202101/2056368-20210106115307148-1750509663.png)
接下來讓我們檢視`check_throttles`,可以看到,驗證訪問頻率的時候,呼叫的方法為頻率驗證類的`allow_request`方法。
![image-20210106122326700](https://img2020.cnblogs.com/blog/2056368/202101/2056368-20210106122327226-603589863.png)
其中`get_throttles`用的還是老套路:
![image-20210106122353228](https://img2020.cnblogs.com/blog/2056368/202101/2056368-20210106122353718-1605526304.png)
## 示例
自定義一個頻率限制類:
```python
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`的處理值得