REST framework 用户认证源码
REST 用戶認(rèn)證源碼
在Django中,從URL調(diào)度器中過來的HTTPRequest會(huì)傳遞給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代碼第三行通過一個(gè)方法initialize_request()重新分裝了原來從URL調(diào)度器傳來的request對象,并且返回的也是一個(gè)request對象,具體分裝的內(nèi)容:
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(), # 用于身份驗(yàn)證negotiator=self.get_content_negotiator(),parser_context=parser_context)initialize_request()返回的是一個(gè)Request對象
class Request(object):def __init__(self, request, parsers=None, authenticators=None,negotiator=None, parser_context=None):passself._request = requestself.parsers = parsers or ()# ...Request這個(gè)類使用"組合"將普通的httprequest分裝在它的內(nèi)部,除此之外還提供了用于身份驗(yàn)證的authenticators,用于解析請求內(nèi)容的解析器(parsers)只關(guān)心authenticators
authenticators由self.get_authenticators()函數(shù)返回,是個(gè)列表
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,并實(shí)例化authentication_classes中的對象加入到列表中返回
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES實(shí)際上authentication_classes只是一個(gè)包含認(rèn)證類的列表
已經(jīng)亂了,整理一下
首先,用戶會(huì)生成一個(gè)httprequest,這個(gè)請求到URL調(diào)度器后會(huì)執(zhí)行as_view()
path('shop/', views.ShopView.as_view())而在as_view()中就會(huì)把這個(gè)原生的httprequest傳遞給dispatch()在dispatch()中會(huì)對這個(gè)httprequest進(jìn)一步封裝,在這里具體就是增加了一個(gè)authenticators,他是一個(gè)列表,列表中是一系列從authentication_classes列表中實(shí)例化出來的對象。
然后進(jìn)入try塊,執(zhí)行self.initial(request, *args, **kwargs),這條語句用來 “運(yùn)行在調(diào)用方法處理程序之前需要發(fā)生的任何事情” 可以說是一個(gè)功能集合,聚合了認(rèn)證管理,權(quán)限管理,版本控制等幾個(gè)功能模塊
def initial(self, request, *args, **kwargs):self.format_kwarg = self.get_format_suffix(**kwargs)# 執(zhí)行內(nèi)容協(xié)商并存儲(chǔ)關(guān)于請求的接受信息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# 用戶認(rèn)證self.perform_authentication(request)# 權(quán)限控制self.check_permissions(request)# 訪問頻率控制self.check_throttles(request)現(xiàn)在只關(guān)心用戶認(rèn)證的工作,進(jìn)入perform_authentication(request)(現(xiàn)在的request已經(jīng)是重新包裝過的的request了),也只有一句話。
def perform_authentication(self, request):request.user它調(diào)用了這個(gè)request對象的user屬性,進(jìn)入user,是一個(gè)屬性方法,主體是調(diào)用了self._authenticate()
@property def user(self):if not hasattr(self, '_user'):# 只是一個(gè)上下文管理器,方便清理之類的工作with wrap_attributeerrors():self._authenticate()return self._user現(xiàn)在是那個(gè)封裝過的request對象調(diào)用了自己的user屬性方法,所以self已經(jīng)是request了,之前是在視圖(view.py)中自己定義的ShopView
進(jìn)入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()他會(huì)遍歷self.authenticators,現(xiàn)在的self是那個(gè)分裝過的request,所以self.authenticators其實(shí)就是上面列表生成式生成的那個(gè)認(rèn)證類對象列表,它遍歷并調(diào)用每一個(gè)認(rèn)證類對象的authenticate方法,這個(gè)方法必須覆蓋,否則會(huì)拋出NotImplementedError異常
def authenticate(self, request):raise NotImplementedError(".authenticate() must be overridden.")這里的邏輯是一旦authenticate()拋出exceptions.APIException異常,就調(diào)用self._not_authenticated()也就是認(rèn)證失敗,如果沒有拋出異常,就進(jìn)入下面的if語句,判斷返回值是否是None如果是,本次循環(huán)就結(jié)束,也就是不使用這個(gè)認(rèn)證類對象,轉(zhuǎn)而使用下一個(gè)認(rèn)證類對象,如果不為None則進(jìn)行一個(gè)序列解包操作,把元組中的第一個(gè)元素賦值給self.user第二個(gè)元素賦值給self.auth,終止循環(huán),如果遍歷完整個(gè)self.authenticators還是沒認(rèn)證成功,就會(huì)執(zhí)行最后一行的self._not_authenticated()和認(rèn)證時(shí)拋出異常一樣,認(rèn)證失敗。
def _not_authenticated(self):"""設(shè)置authenticator,user&authToken表示未經(jīng)過身份驗(yàn)證的請求。默認(rèn)值為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認(rèn)證失敗后的邏輯是:先看配置文件中有沒有UNAUTHENTICATED_USER,如果有,就把這個(gè)配置內(nèi)容作為默認(rèn)的“匿名用戶”,否則就把self.user賦值為None,self.auth也一樣。
這大概就是認(rèn)證的基本流程了。
過程總結(jié)
用戶發(fā)出請求,產(chǎn)生request,傳遞到URL調(diào)度器,url調(diào)度器將request傳遞給as_view(),as_view()再傳遞給dispatch(),在這里會(huì)給原來的request封裝用來身份驗(yàn)證的authenticators,他是一個(gè)儲(chǔ)存認(rèn)證類對象的列表,封裝完成后遍歷這個(gè)列表,如果拋出exceptions.APIException異常,認(rèn)證失敗,使用匿名用戶登錄,否則如果返回一個(gè)二元組,就將他們分別賦值給user和auth,如果返回None,同樣認(rèn)證失敗,使用匿名用戶登錄。
全局驗(yàn)證
可以設(shè)置對所有視圖驗(yàn)證,因?yàn)?/p> 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'] }就可以設(shè)置所有視圖都要使用MyAuthentication驗(yàn)證,如果由別的視圖不需要驗(yàn)證,可在視圖類內(nèi)把a(bǔ)uthentication_classes設(shè)置為空列表。
總結(jié)
以上是生活随笔為你收集整理的REST framework 用户认证源码的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 乌班图系统设置系统语言,以及中文输入法
- 下一篇: 通信协议(二)——SPI协议