REST framework 用戶認證源碼

REST 用戶認證源碼

在Django中,從URL調度器中過來的HTTPRequest會傳遞給disatch(),使用REST后也一樣

# REST的dispatch
def dispatch(self, request, *args, **kwargs):"""`.dispatch()` is pretty much the same as Django's regular dispatch,but with extra hooks for startup, finalize, and exception handling."""self.args = argsself.kwargs = kwargsrequest = self.initialize_request(request, *args, **kwargs)self.request = requestself.headers = self.default_response_headers  # deprecate?try:self.initial(request, *args, **kwargs)# Get the appropriate handler methodif request.method.lower() in self.http_method_names:handler = getattr(self, request.method.lower(),self.http_method_not_allowed)else:handler = self.http_method_not_allowedresponse = handler(request, *args, **kwargs)except Exception as exc:response = self.handle_exception(exc)self.response = self.finalize_response(request, response, *args, **kwargs)return self.response

代碼第三行通過一個方法initialize_request()重新分裝了原來從URL調度器傳來的request對象,并且返回的也是一個request對象,具體分裝的內容:

    def initialize_request(self, request, *args, **kwargs):"""Returns the initial request object."""parser_context = self.get_parser_context(request)return Request(request,parsers=self.get_parsers(), # 解析器authenticators=self.get_authenticators(), # 用于身份驗證negotiator=self.get_content_negotiator(),parser_context=parser_context)

initialize_request()返回的是一個Request對象

class Request(object):def __init__(self, request, parsers=None, authenticators=None,negotiator=None, parser_context=None):passself._request = requestself.parsers = parsers or ()# ...

Request這個類使用"組合"將普通的httprequest分裝在它的內部,除此之外還提供了用于身份驗證的authenticators,用于解析請求內容的解析器(parsers)只關心authenticators

authenticators由self.get_authenticators()函數返回,是個列表

def get_authenticators(self):"""Instantiates and returns the list of authenticators that this view can use."""return [auth() for auth in self.authentication_classes]

get_authenticators遍歷authentication_classes,并實例化authentication_classes中的對象加入到列表中返回

authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES

實際上authentication_classes只是一個包含認證類的列表


已經亂了,整理一下

首先,用戶會生成一個httprequest,這個請求到URL調度器后會執行as_view()

path('shop/', views.ShopView.as_view())

而在as_view()中就會把這個原生的httprequest傳遞給dispatch()dispatch()中會對這個httprequest進一步封裝,在這里具體就是增加了一個authenticators,他是一個列表,列表中是一系列從authentication_classes列表中實例化出來的對象。


然后進入try塊,執行self.initial(request, *args, **kwargs),這條語句用來 “運行在調用方法處理程序之前需要發生的任何事情” 可以說是一個功能集合,聚合了認證管理,權限管理,版本控制等幾個功能模塊

def initial(self, request, *args, **kwargs):self.format_kwarg = self.get_format_suffix(**kwargs)# 執行內容協商并存儲關于請求的接受信息neg = self.perform_content_negotiation(request)request.accepted_renderer, request.accepted_media_type = neg# 版本控制version, scheme = self.determine_version(request, *args, **kwargs)request.version, request.versioning_scheme = version, scheme# 用戶認證self.perform_authentication(request)# 權限控制self.check_permissions(request)# 訪問頻率控制self.check_throttles(request)

現在只關心用戶認證的工作,進入perform_authentication(request)(現在的request已經是重新包裝過的的request了),也只有一句話。

def perform_authentication(self, request):request.user

它調用了這個request對象的user屬性,進入user,是一個屬性方法,主體是調用了self._authenticate()

@property
def user(self):if not hasattr(self, '_user'):# 只是一個上下文管理器,方便清理之類的工作with wrap_attributeerrors():self._authenticate()return self._user

現在是那個封裝過的request對象調用了自己的user屬性方法,所以self已經是request了,之前是在視圖(view.py)中自己定義的ShopView

進入self._authenticate()

    def _authenticate(self):for authenticator in self.authenticators:try:user_auth_tuple = authenticator.authenticate(self)except exceptions.APIException:self._not_authenticated()raiseif user_auth_tuple is not None:self._authenticator = authenticatorself.user, self.auth = user_auth_tuplereturnself._not_authenticated()

他會遍歷self.authenticators,現在的self是那個分裝過的request,所以self.authenticators其實就是上面列表生成式生成的那個認證類對象列表,它遍歷并調用每一個認證類對象的authenticate方法,這個方法必須覆蓋,否則會拋出NotImplementedError異常

def authenticate(self, request):raise NotImplementedError(".authenticate() must be overridden.")

這里的邏輯是一旦authenticate()拋出exceptions.APIException異常,就調用self._not_authenticated()也就是認證失敗,如果沒有拋出異常,就進入下面的if語句,判斷返回值是否是None如果是,本次循環就結束,也就是不使用這個認證類對象,轉而使用下一個認證類對象,如果不為None則進行一個序列解包操作,把元組中的第一個元素賦值給self.user第二個元素賦值給self.auth,終止循環,如果遍歷完整個self.authenticators還是沒認證成功,就會執行最后一行的self._not_authenticated()和認證時拋出異常一樣,認證失敗。

def _not_authenticated(self):"""設置authenticator,user&authToken表示未經過身份驗證的請求。默認值為None,AnonymousUser&None。"""self._authenticator = Noneif api_settings.UNAUTHENTICATED_USER:self.user = api_settings.UNAUTHENTICATED_USER()else:self.user = Noneif api_settings.UNAUTHENTICATED_TOKEN:self.auth = api_settings.UNAUTHENTICATED_TOKEN()else:self.auth = None

認證失敗后的邏輯是:先看配置文件中有沒有UNAUTHENTICATED_USER,如果有,就把這個配置內容作為默認的“匿名用戶”,否則就把self.user賦值為None,self.auth也一樣。


這大概就是認證的基本流程了。

過程總結

用戶發出請求,產生request,傳遞到URL調度器,url調度器將request傳遞給as_view()as_view()再傳遞給dispatch(),在這里會給原來的request封裝用來身份驗證的authenticators,他是一個儲存認證類對象的列表,封裝完成后遍歷這個列表,如果拋出exceptions.APIException異常,認證失敗,使用匿名用戶登錄,否則如果返回一個二元組,就將他們分別賦值給user和auth,如果返回None,同樣認證失敗,使用匿名用戶登錄。

全局驗證

可以設置對所有視圖驗證,因為

authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
def reload_api_settings(*args, **kwargs):setting = kwargs['setting']if setting == 'REST_FRAMEWORK':api_settings.reload()

所以在Django的配置文件中添加

REST_FRAMEWORK = {'DEFAULT_AUTHENTICATION_CLASSES': ['demo.utils.MyAuthentication.MyAuthentication']
}

就可以設置所有視圖都要使用MyAuthentication驗證,如果由別的視圖不需要驗證,可在視圖類內把authentication_classes設置為空列表。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/457530.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/457530.shtml
英文地址,請注明出處:http://en.pswp.cn/news/457530.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

scrapyd部署_如何通過 Scrapyd + ScrapydWeb 簡單高效地部署和監控分布式爬蟲項目

來自 Scrapy 官方賬號的推薦需求分析初級用戶:只有一臺開發主機能夠通過 Scrapyd-client 打包和部署 Scrapy 爬蟲項目,以及通過 Scrapyd JSON API 來控制爬蟲,感覺 命令行操作太麻煩 ,希望能夠通過瀏覽器直接部署和運行項目專業用…

最長上升子序列 (LIS算法(nlong(n)))

設 A[t]表示序列中的第t個數&#xff0c;F[t]表示從1到t這一段中以t結尾的最長上升子序列的長度&#xff0c;初始時設F [t] 0(t 1, 2, ..., len(A))。則有動態規劃方程&#xff1a;F[t] max{1, F[j] 1} (j 1, 2, ..., t - 1, 且A[j] < A[t])。 現在&#xff0c;我們仔細…

牛頓插值--python實現

from tabulate import tabulate import sympy""" 牛頓插值法 """class NewtonInterpolation:def __init__(self, x: list, y: list):self.Xi = xself

css搖曳的_HTML5+CSS3實現樹被風吹動搖晃

1新建html文檔。2書寫hmtl代碼。3書寫css代碼。.trunk, .trunk div { background: #136086; width: 100px; height: 10px; position: absolute; left: 50%; top: 70%; margin-left: -10px; -webkit-animation-name: rot; animation-name: rot; -webkit-animation-duration: 2.0…

素數路(prime)

素數路(prime) 題目描述 已知一個四位的素數&#xff0c;要求每次修改其中的一位&#xff0c;并且要保證修改的結果還是一個素數&#xff0c;還不能出現前導零。你要找到一個修改數最少的方案&#xff0c;得到我們所需要的素數。 例如把1033變到8179&#xff0c;這里是一個最短…

python多線程單核_002_Python多線程相當于單核多線程的論證

很多人都說python多線程是假的多線程!下面進行論證解釋:一、我們先明確一個概念&#xff0c;全局解釋器鎖(GIL)Python代碼的執行由Python虛擬機(解釋器)來控制。Python在設計之初就考慮要在主循環中&#xff0c;同時只有一個線程在執行&#xff0c;就像單CPU的系統中運行多個進…

detail:JSON parse error - Expecting value: line 1 column 1 (char 0)

detail":"JSON parse error - Expecting value: line 1 column 1 (char 0) 在調用接口時返回400錯誤&#xff0c;詳情是 {detail":"JSON parse error - Expecting value: line 1 column 1 (char 0)"}原因是傳送數據的格式有問題&#xff0c;不要使用…

【IDEA 2016】intellij idea tomcat jsp 熱部署

剛開始用IDEA&#xff0c;落伍的我&#xff0c;只是覺得IDEA好看。可以換界面。想法如此的low。 真是不太會用啊&#xff0c;弄好了tomcat。程序啟動竟然改動一下就要重啟&#xff0c;JSP頁面也一樣。 IDEA可以配置熱部署&#xff0c;打開tomcat配置頁面&#xff0c;將紅框處&a…

C# where用法解析

where 子句用于指定類型約束&#xff0c;這些約束可以作為泛型聲明中定義的類型參數的變量。1.接口約束。例如&#xff0c;可以聲明一個泛型類 MyGenericClass&#xff0c;這樣&#xff0c;類型參數 T 就可以實現 IComparable<T> 接口&#xff1a;public class MyGeneric…

ubuntu進入桌面自動啟動腳本_在 Ubuntu 下開機自啟動自己的 QT 程序而不啟動 Ubuntu 的桌面...

1. /etc/profile 方式實現這個功能&#xff0c;要完成兩步&#xff1a;1、系統設置-> 用戶賬戶-> 點擊我的賬戶-> 點擊右上角的解鎖-> 打開自動登錄-> 點擊右上角的鎖定-> 退出系統設置2、在 /etc/profile 文件的開頭添加執行 qt 程序的命令。如&#xff1a;…

Java obj與JSON互轉(jackson)

JSON 解析 常見的json解析器&#xff1a; jsonlibGson(谷歌)fastjson(阿里)jackson(Spring內置) jackson 依賴jar包 jackson-annotations/jackson-core/jackson-databind/ 官網下載地址 1. Java對象轉JSON 1.1 核心對象 ObjectMapper 1.2常用轉換方法 writeValue(參…

如何制作一個簡單的APP應用軟件?

如今隨著移動智能手機的普及&#xff0c;讓APP的市場一片繁榮&#xff0c;現在市場上的APP數量數不勝數&#xff0c;對于APP開發的我們很多外行人也許認為&#xff0c;開發APP是不是特別難&#xff0c;是不是只有資歷很高的程序員才能夠完成這個任務&#xff0c;或者說要想開發…

I/O重定向

每個進程都至少有3個信息&#xff1a;“標準輸入”stdin、“標準輸出”stdout、和“標準出錯”stderr。標準輸入通常來自鍵盤&#xff0c;標準輸出和標準錯誤輸出通常被發往屏幕&#xff08;并不會保存在磁盤文件中&#xff09;。有些時候&#xff0c;需要從文件讀取輸入&#…

java 自動裝拆箱

title: “java 自動裝拆箱” tags: Java 將基本數據類型封裝成對象的過程叫做裝箱&#xff08;boxing&#xff09;&#xff0c;反之基本數據類型對應的包裝類轉換為基本數據類型的過程叫做拆箱&#xff08;unboxing&#xff09;; 基本數據類型與其他對象的區別 基本數據類型 …

設計模式11---組合模式(Composite Pattern)

一、組合模式定義 將對象組合成樹形結構以表示“部分-整體”的層次結構&#xff0c;使得用戶對單個對象和組合對象的使用具有一致性。Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compos…

Linux 多核下綁定硬件中斷到不同 CPU(IRQ Affinity)

轉載 - Linux 多核下綁定硬件中斷到不同 CPU&#xff08;IRQ Affinity&#xff09; 作者 digoal 日期 2016-11-20 標簽 Linux , IRQ , 中斷 , CPU親和 , 綁定中斷處理CPU 背景 原文 http://www.vpsee.com/2010/07/load-balancing-with-irq-smp-affinity/ 原文 硬件中斷發生頻繁…

請列舉你了解的分布式鎖_這幾種常見的“分布式鎖”寫法,搞懂再也不怕面試官,安排!...

什么是分布式鎖&#xff1f;大家好&#xff0c;我是jack xu&#xff0c;今天跟大家聊一聊分布式鎖。首先說下什么是分布式鎖&#xff0c;當我們在進行下訂單減庫存&#xff0c;搶票&#xff0c;選課&#xff0c;搶紅包這些業務場景時&#xff0c;如果在此處沒有鎖的控制&#x…

leetcode 268

等差數列求值 1 class Solution {2 public:3 int missingNumber(vector<int>& nums) {4 int nnums.size();5 int kn*(n1)/2;6 for(int i0;i<n;i)7 k-nums[i];8 return k;9 } 10 }; 轉載于:https://www.cnblogs.…

301緩存重定向?301 Moved Permanently (from disk cache)

今天在寫一個博客系統時&#xff0c;發現首頁數據經常刷新不出來&#xff0c;甚至后端根本就沒有接受到這個請求&#xff0c;以為是Ajax的問題&#xff0c;但通過抓包發現Ajax請求確實已經發出去了&#xff0c;但狀態碼是 301 Moved Permanently (from disk cache),301是永久重…

Firefox 50優化Electrolysis

Mozilla正式發布Firefox 50。最新的版本中提升了來自多個內容進程用戶的用戶體驗&#xff0c;并修復了十幾個高影響的安全漏洞。\\在Firefox最新版本的變更中&#xff0c;我們注意到了它對于Electrolysis的進一步改進。Electrolysis是Mozilla實現在后臺進程中呈現和執行web相關…