# 課程鏈接
4天搞定django rest framework源碼和實戰_哔哩哔哩_bilibili
# 課程內容
(1)rest framework之權限源碼流程
(2)rest framework之權限的內置類
(3)rest framework之訪問頻率控制基本實現
(4)rest framework之訪問頻率控制源碼流程
(5)rest framework之基於內置類實現訪問頻率控制
(6)rest framework之訪問頻率內容梳理
【補充知識】
# (1)權限認證的源碼流程,自己寫的。
1)總之和用戶認證的配置是差不多的。
# (1)內置的權限規則 BasePermission 類
1)要使用的時候直接 from rest_framework.permissions import BasePermission 即可。下圖是源碼,這裡需要說明一下,今後我們自定義類的時候,一律繼承這個內置類。 這算是一種規范。
# (2)小總結,重點還是看源碼
# (1)訪問控制的思路
1)為了便於描述,我們直接上武sir 的筆記。假設用戶 C 訪問了服務端 S,且一分鐘內只能訪問三次,訪問記錄是一個字典,字典的一個字段對應一個用戶的 IP。當 C 訪問的時候,會拿到 C 的 ip 地址並在訪問記錄字典中,生成對應的字段,值是一個列表,列表中記錄了 C 一分鐘內的所有訪問時間(可能是訪問了 1 次,也可能是 3 次)。
如下圖所示,比如 C 的第一次訪問的時間是 12:10:05(服務端的計時),那麼此時 C 的訪問的列表 : [12: 10: 05] ,如果在 1 分鐘內發生了總共三次的訪問,那麼訪問列表, :[12:10:07,12:10:06,12: 10: 05] (可以看到最早訪問在列表的最後,類似隊列)。當第 4 次訪問進來的時候,設此時為 T 時刻(服務端的計時)。服務端會首先讓 T 減去 1 分鐘,記 (T -60s)然後從列表最後的一個時間開始(即逆向),依次和列表的時間比較,記列表最後的那個時間為t (就是最早進來的時間),如果 t > (T - 60s),那麼肯定當前的 T 還在一分鐘內,故而不能訪問;如果依次比較,(T - 60s)比所有時間到大,顯然可以訪問,那麼就直接清空原列表,此時新列表為 : [ T ];其余情況依此類推。【其實真實的時候,可能不只是用 ip。因為 IP 雖然是用戶的唯一標識,但還是可以通過掛代理的方式換 IP 來突破訪問的限制。除非是注冊用戶,這樣子我們存的唯一標識就是用戶名等信息了,當然如果有水軍也沒轍】
2) 小總結
# (2)基於上述訪問原理的一個小實戰
直接上代碼,我們依舊是自定義一個節流類,基本的應用方法,也是和前面的一樣的。然後我們基於上面的原理實現了如下的代碼。值得一提的是 wait() 方法是返回告訴用戶還有多久時間才能夠繼續訪問的。具體的局部配置,也是類似認證和權限的套路。【節流這一個和 drf 的思路是一樣的】
# -*- coding=utf-8 -*- # github: night_walkiner # csdn: 潘迪仔 import time VISIT_RECORD = {} # 默認放在緩存的 class VisitThrottle(object): def __init__(self): # 初始化 self.history = None def allow_request(self, request, view): # (1) 獲取 遠程主機的 ip 地址 # request.META.get("REMOTE_ADDR") 是獲取遠程主機的地址 # 這是drf內置的,也可以使用語句 request._request.META.get("REMOTE_ADDR"), # 事實上 drf 給我們封裝的 request ,如果某些方法封裝的 request 找不到,就會去 request._request 中找 remote_addr = request.META.get("REMOTE_ADDR") # (2) 記錄當前訪問的時間 ctime = time.time() # (3) 判斷遠程 ip 地址是不是在我們的訪問記錄中,如果是第一次訪問,就添加相應的字段 if not VISIT_RECORD.get(remote_addr): VISIT_RECORD[remote_addr] = [ctime, ] return True history = VISIT_RECORD.get(remote_addr) self.history = history # (4) 第二次訪問的時候 while history and history[-1] < ctime - 10: history.pop() if len(history) < 3: history.insert(0, ctime) VISIT_RECORD[remote_addr] = history return True return None def wait(self): """這個函數是提示,再等多少秒就能訪問了""" # 計算剩余的時間 ctime = time.time() return 60 - (ctime - self.history[-1])
# (1)我們直接上流程圖把
# (1)內置的訪問頻率控制類
1)BaseThrottle() 內,如下圖就是我們的內置的基本訪問頻率控制類的源碼,具體的源碼注釋如下。BaseThrottle() 是通過 from rest_framework.throttling import BaseThrottle 的方法來導入的,之後寫自定義的訪問頻率控制規則的時候,可以繼承該類來寫。【另外在 IP 中的代理問題,可以參考一下鏈接:HTTP_X_FORWARDED_FOR獲取到的IP地址_ccfxue的博客-CSDN博客】
2)SimpleRateThrottle() 類就是 drf 給我們提供的一個較為完善的頻率訪問控制類,事實上就跟我們上面自定義的規則類似,流程也相似。今後我們也可以繼承這個類來進一步的自定義我們的訪問頻率控制。
3)SimpleRateThrottle() 類的源碼流程解讀。
# (2)基於內置類來實現訪問頻率控制
1)首先是配置一下全局的配置,即設置 self.rate 的值
2)那麼視圖類的代碼如下:
3)上述的是針對匿名用戶的控制,如果是針對於已注冊的用戶。那麼我們也給出相應的配置和源碼。
視圖類的代碼
關於全局配置的,可以看視頻的後半段的。鏈接如下:
4天搞定django rest framework源碼和實戰_哔哩哔哩_bilibili
# (1)內容梳理
#(1)self.__class__.__name__ 的意思
1)簡單說就是獲得這個類的類名,如果是 list 或者 dict 的話,那麼其實取到的分別就是 list 和 dict。
【歡迎指正和補充】