日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

REST framework 用户认证源码

發布時間:2023/12/20 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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設置為空列表。

總結

以上是生活随笔為你收集整理的REST framework 用户认证源码的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。