Python學習————drf(七)
阿新 • • 發佈:2020-07-14
1 自定製頻率
# 自定製頻率類,需要寫兩個方法 -# 判斷是否限次:沒有限次可以請求True,限次了不可以請求False def allow_request(self, request, view): -# 限次後呼叫,顯示還需等待多長時間才能再訪問,返回等待的時間seconds def wait(self): # 程式碼 import time class IPThrottle(): #定義成類屬性,所有物件用的都是這個 VISIT_DIC = {} def __init__(self): self.history_list=[] def allow_request(self, request, view): ''' #(1)取出訪問者ip #(2)判斷當前ip不在訪問字典裡,新增進去,並且直接返回True,表示第一次訪問,在字典裡,繼續往下走 #(3)迴圈判斷當前ip的列表,有值,並且當前時間減去列表的最後一個時間大於60s,把這種資料pop掉,這樣列表中只有60s以內的訪問時間, #(4)判斷,當列表小於3,說明一分鐘以內訪問不足三次,把當前時間插入到列表第一個位置,返回True,順利通過 #(5)當大於等於3,說明一分鐘內訪問超過三次,返回False驗證失敗 ''' ip=request.META.get('REMOTE_ADDR') ctime=time.time() if ip not in self.VISIT_DIC: self.VISIT_DIC[ip]=[ctime,] return True self.history_list=self.VISIT_DIC[ip] #當前訪問者時間列表拿出來 while True: if ctime-self.history_list[-1]>60: self.history_list.pop() # 把最後一個移除 else: break if len(self.history_list)<3: self.history_list.insert(0,ctime) return True else: return False def wait(self): # 當前時間,減去列表中最後一個時間 ctime=time.time() return 60-(ctime-self.history_list[-1]) #全域性使用,區域性使用
# SimpleRateThrottle原始碼分析 def get_rate(self): """ Determine the string representation of the allowed request rate. """ if not getattr(self, 'scope', None): msg = ("You must set either `.scope` or `.rate` for '%s' throttle" % self.__class__.__name__) raise ImproperlyConfigured(msg) try: return self.THROTTLE_RATES[self.scope] # scope:'user' => '3/min' except KeyError: msg = "No default throttle rate set for '%s' scope" % self.scope raise ImproperlyConfigured(msg) def parse_rate(self, rate): """ Given the request rate string, return a two tuple of: <allowed number of requests>, <period of time in seconds> """ if rate is None: return (None, None) #3 mmmmm num, period = rate.split('/') # rate:'3/min' num_requests = int(num) duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]] return (num_requests, duration) def allow_request(self, request, view): if self.rate is None: return True #當前登入使用者的ip地址 self.key = self.get_cache_key(request, view) # key:'throttle_user_1' if self.key is None: return True # 初次訪問快取為空,self.history為[],是存放時間的列表 self.history = self.cache.get(self.key, []) # 獲取一下當前時間,存放到 self.now self.now = self.timer() # Drop any requests from the history which have now passed the # throttle duration # 當前訪問與第一次訪問時間間隔如果大於60s,第一次記錄清除,不再算作一次計數 # 10 20 30 40 # self.history:[10:23,10:55] # now:10:56 while self.history and self.now - self.history[-1] >= self.duration: self.history.pop() # history的長度與限制次數3進行比較 # history 長度第一次訪問0,第二次訪問1,第三次訪問2,第四次訪問3失敗 if len(self.history) >= self.num_requests: # 直接返回False,代表頻率限制了 return self.throttle_failure() # history的長度未達到限制次數3,代表可以訪問 # 將當前時間插入到history列表的開頭,將history列表作為資料存到快取中,key是throttle_user_1,過期時間60s return self.throttle_success()
2 自動生成介面文件
# 1 安裝:pip install coreapi # 2 在路由中配置 from rest_framework.documentation import include_docs_urls urlpatterns = [ ... path('docs/', include_docs_urls(title='站點頁面標題')) ] #3 檢視類:自動介面文件能生成的是繼承自APIView及其子類的檢視。 -1 ) 單一方法的檢視,可直接使用類檢視的文件字串,如 class BookListView(generics.ListAPIView): """ 返回所有圖書資訊. """ -2)包含多個方法的檢視,在類檢視的文件字串中,分開方法定義,如 class BookListCreateView(generics.ListCreateAPIView): """ get: 返回所有圖書資訊. post: 新建圖書. """ -3)對於檢視集ViewSet,仍在類檢視的文件字串中封開定義,但是應使用action名稱區分,如 class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet): """ list: 返回圖書列表資料 retrieve: 返回圖書詳情資料 latest: 返回最新的圖書資料 read: 修改圖書的閱讀量 """
3 JWT
jwt=Json Web token
#原理
"""
1)jwt分三段式:頭.體.簽名 (head.payload.sgin)
2)頭和體是可逆加密,讓伺服器可以反解出user物件;簽名是不可逆加密,保證整個token的安全性的
3)頭體簽名三部分,都是採用json格式的字串,進行加密,可逆加密一般採用base64演算法,不可逆加密一般採用hash(md5)演算法
4)頭中的內容是基本資訊:公司資訊、專案組資訊、token採用的加密方式資訊
{
"company": "公司資訊",
...
}
5)體中的內容是關鍵資訊:使用者主鍵、使用者名稱、簽發時客戶端資訊(裝置號、地址)、過期時間
{
"user_id": 1,
...
}
6)簽名中的內容時安全資訊:頭的加密結果 + 體的加密結果 + 伺服器不對外公開的安全碼 進行md5加密
{
"head": "頭的加密字串",
"payload": "體的加密字串",
"secret_key": "安全碼"
}
"""
校驗
"""
1)將token按 . 拆分為三段字串,第一段 頭加密字串 一般不需要做任何處理
2)第二段 體加密字串,要反解出使用者主鍵,通過主鍵從User表中就能得到登入使用者,過期時間和裝置資訊都是安全資訊,確保token沒過期,且時同一裝置來的
3)再用 第一段 + 第二段 + 伺服器安全碼 不可逆md5加密,與第三段 簽名字串 進行碰撞校驗,通過後才能代表第二段校驗得到的user物件就是合法的登入使用者
"""
drf專案的jwt認證開發流程(重點)
"""
1)用賬號密碼訪問登入介面,登入介面邏輯中呼叫 簽發token 演算法,得到token,返回給客戶端,客戶端自己存到cookies中
2)校驗token的演算法應該寫在認證類中(在認證類中呼叫),全域性配置給認證元件,所有檢視類請求,都會進行認證校驗,所以請求帶了token,就會反解出user物件,在檢視類中用request.user就能訪問登入的使用者
注:登入介面需要做 認證 + 許可權 兩個區域性禁用
"""
# 第三方寫好的 django-rest-framework-jwt
# 安裝pip install djangorestframework-jwt
# 新建一個專案,繼承AbstractUser表()
# 建立超級使用者
# 簡單使用
#urls.py
from rest_framework_jwt.views import ObtainJSONWebToken,VerifyJSONWebToken,RefreshJSONWebToken,obtain_jwt_token
path('login/', obtain_jwt_token),
自定製auth認證類
from rest_framework_jwt.authentication import BaseAuthentication,BaseJSONWebTokenAuthentication
from rest_framework.exceptions import AuthenticationFailed
from rest_framework_jwt.authentication import jwt_decode_handler
from rest_framework_jwt.authentication import get_authorization_header,jwt_get_username_from_payload
from rest_framework import exceptions
class MyToken(BaseJSONWebTokenAuthentication):
def authenticate(self, request):
jwt_value=str(request.META.get('HTTP_AUTHORIZATION'))
# 認證
try:
payload = jwt_decode_handler(jwt_value)
except Exception:
raise exceptions.AuthenticationFailed("認證失敗")
user=self.authenticate_credentials(payload)
return user,None
#區域性使用,全域性使用