DRF認(rèn)證

單獨看用法

你定義了一個類CBV经柴,類繼承自APIView丈探,在里面賦值authentication_classes字段欺殿,字段認(rèn)證類列表橡娄,這幾個認(rèn)證類都需要你自己定義诗箍。認(rèn)證類中要實現(xiàn)authenticate()方法和authenticate_header()方法

  • 認(rèn)證類一般繼承BaseAuthentication類,然后重寫authenticate方法
  • authenticate方法需要返回一個元組挽唉,第一個對象為用戶實例滤祖,第二個為Token實例
class Authentication1():
    def authenticate(self, request):
        token_obj = request._request.GET.get('token')
        if not token_obj:
            raise exception.AuthenticationFailed('用戶認(rèn)證失敗')
        return (token_obj.user, token_obj)
     
     def authenticate_header(self, request):
        pass
##################################
from restframework.views import APIView
class OrderView(APIView):
    authentication_classes = [Authentication1,  Authentication2]
    def get(self, request):
        pass

源碼流程

  • 當(dāng)調(diào)用OrderView時,執(zhí)行dispatch()方法瓶籽,此方法將request對象做了一個封裝匠童,request = self.initialize_request,然后將此視圖類進(jìn)行初始化塑顺,最后進(jìn)行根據(jù)字符串進(jìn)行反射汤求,執(zhí)行對應(yīng)的函數(shù)。
  • 我們到initialize_request方法中严拒,看到了具體的封裝信息扬绪,返回的是一個Request類型的對象,里面有原來的request裤唠,還加了許多新的屬性
        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )

我們看到了authenticators = self.get_authenticators()

  • 我們到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]

他其實就是返回了一個對象列表挤牛,每一個對象都是authentication_classes列表中的認(rèn)證類的實例。里面的authenticators的值也得到了种蘸,現(xiàn)在得到了Request對象墓赴。

  • 在dispatch中,得到了Response對象劈彪,然后是初始化 視圖類 竣蹦,執(zhí)行self.initial(),最后是執(zhí)行相應(yīng)的函數(shù)。

在執(zhí)行初始化操作中沧奴,其他的先別看痘括,先看self.perform_authentication(request)方法

        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)

這個方法就一句,self.user 沒有return。所以我們到Request對象中看有沒有user屬性纲菌,request.user執(zhí)行的結(jié)果就是self._authenticate方法挠日,還是Request對象的方法。

    def _authenticate(self):
        """
        Attempt to authenticate the request using each authentication instance
        in turn.
        """
        for authenticator in self.authenticators:
            try:
                user_auth_tuple = authenticator.authenticate(self)
            except exceptions.APIException:
                self._not_authenticated()
                raise

            if user_auth_tuple is not None:
                self._authenticator = authenticator
                self.user, self.auth = user_auth_tuple
                return

        self._not_authenticated()

self.authenticators我們已經(jīng)得到了翰舌,是一個認(rèn)證類實例的列表嚣潜,遍歷列表,并認(rèn)證類對象的authenticate()方法椅贱,返回異常懂算,或者self.user,self.auth = (元組,且必須兩個值,),這個就是自定義認(rèn)證類的返回結(jié)果庇麦。
還有就是所有認(rèn)證都不管计技,返回默認(rèn)的self.user,self.auth = (匿名用戶,None)

再看源碼山橄,了解全局配置

  • 源碼中每次調(diào)用的都會先找自己類中有沒有 authentication_classes垮媒,沒有再去全局中找authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES,所以我們可以給全局設(shè)置一個值航棱,當(dāng)自己類中沒有時睡雇,來全局中找。
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES':[‘a(chǎn)pp1.utils.auth.Authentication’,‘ app1.utils.auth.Authentication2’ ]
}
  • 這樣寫饮醇,你的繼承自APIView的所有的類都會到app1.utils下面的auth.py中找到Authentication和Authentication2進(jìn)行認(rèn)證它抱,不想認(rèn)證的類可以在自己類的內(nèi)部定義一個空的authtication_classes = [ ] 列表。
    —————————————————————————————————————

  • 其實這就是配置項驳阎,讓REST_FRAMEWORK的配置項工作抗愁,設(shè)置其默認(rèn)的authentication_classes為后面的類。就無需在類中定義了呵晚,訪問時,用的就是修改后的默認(rèn)值沫屡。

  • 除了DEFAULT_AUTHENTICATION_CLASSES配置饵隙,還可以設(shè)置其他的。
    renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
    parser_classes = api_settings.DEFAULT_PARSER_CLASSES
    authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
    throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
    permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
    content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
    metadata_class = api_settings.DEFAULT_METADATA_CLASS
    versioning_class = api_settings.DEFAULT_VERSIONING_CLASS

如果認(rèn)證失敗的話沮脖,

        if api_settings.UNAUTHENTICATED_USER:
            self.user = api_settings.UNAUTHENTICATED_USER()
        else:
            self.user = None

        if api_settings.UNAUTHENTICATED_TOKEN:
            self.auth = api_settings.UNAUTHENTICATED_TOKEN()
        else:
            self.auth = None

requesr.user = api_settings.UNAUTHENTICATED_USER(),
request.auth = api_settings.UNAUTHENTICATED_TOKEN()
所以在配置項中

    'UNAUTHENTICATED_USER':None,
    # 'UNAUTHENTICATED_USER':lambda :"匿名用戶",
    'UNAUTHENTICATED_TOKEN':None,

設(shè)置未登錄的request.user = None,和request.auth = None方便判斷金矛。

為什么要加token進(jìn)行身份驗證呢?

  • 因為源碼中APIView的view被裝飾器csrf _exempt裝飾勺届,此類有csrf驗證的豁免權(quán)驶俊。
    所以我們要把身份驗證加上

restframework中的認(rèn)證類

BasicAuthentication,瀏覽器對你的用戶名和密碼進(jìn)行加密免姿,放到header中饼酿,在你的header中有加密后的用戶名和密碼,他會到header中取得加密的值,然后進(jìn)行解密故俐,得到用戶名和密碼進(jìn)行驗證想鹰。

梳理

梳理:

  1. 創(chuàng)建類,繼承BaseAuthentication药版,重寫方法(其中第一個必須重寫)
    2.1 全局使用
    在settings中添加restframework配置項
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES':[‘a(chǎn)pp1.utils.auth.Authentication’,‘ app1.utils.auth.Authentication2’ ],
    'UNAUTHENTICATED_USER':None,
    # 'UNAUTHENTICATED_USER':lambda :"匿名用戶",
    'UNAUTHENTICATED_TOKEN':None,
}
  1. 2 局部使用/或不使用
    在創(chuàng)建的類中添加靜態(tài)字段authentications_classses = [‘認(rèn)證類路徑’]或者 = []空列表

再來一遍源碼流程

dispatch --> 封裝了request辑舷,獲取定義的認(rèn)證類,然后通過列表生成式創(chuàng)建認(rèn)證類的對象槽片,在執(zhí)行類初始化時何缓,會調(diào)用類的performe_authencation方法,到request.user还栓,到for循環(huán)認(rèn)證類對象碌廓,并調(diào)用他的_authenticate()方法進(jìn)行認(rèn)證,得到三種結(jié)果蝙云,認(rèn)證成功氓皱,認(rèn)證失敗,不進(jìn)行認(rèn)證勃刨。request.user = 用戶名或者None或者匿名用戶,request.auth = token或者None

使用代碼

utils.auth.py 認(rèn)證類

from rest_framework.authentication import BaseAuthentication

class Authentication(BaseAuthentication):
    '''自定義的認(rèn)證類'''
    def authenticate(self, request):
        pass # 具體認(rèn)證邏輯
        '''
        token = request._request.GET.get('token')
        token_obj = model.UserToken.objects.filter(token=token).first()
        
        if not token_obj:
            :raiseexception.AuthenticationFailed('用戶認(rèn)證失敗')
        return (token_obj.user, token_obj) # 把元組的元素賦值為request.user 和 request.auth
        '''
    def authenticate_header(self, request):
        pass

views.py 視圖函數(shù)

from rest_framework.views import APIView
from utils.auth import Authentication
from django.http import JsonResponse
class OrderView(APIView):
    authentication_classes = [Authentication,]  # 局部引用

    def get(self,request):

        ret = {'code':10000,'msg':None}
        try:
            pass # 具體視圖函數(shù)邏輯
        except Exception as e:
            pass  # 拋出異常
        return JsonResponse(ret)

settings.py 全局配置

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES':['app1.utils.auth.Authentication',],

      'UNAUTHENTICATED_USER':None,  # 默認(rèn)匿名用戶配置
      # 'UNAUTHENTICATED_USER':lambda :"匿名用戶",  # 不如上面的好用波材,直接判斷None

      'UNAUTHENTICATED_TOKEN':None,  # 默認(rèn)匿名用戶的auth
}

拓展

認(rèn)證信息可以放在header中,request.META可以獲取header中的信息
默認(rèn)的認(rèn)證信息為Authoriation身隐,所以獲取可以通過加上HTTP_前綴+大寫鍵廷区。

request.META.get('HTTP_AUTHORIATION')
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市贾铝,隨后出現(xiàn)的幾起案子隙轻,更是在濱河造成了極大的恐慌,老刑警劉巖垢揩,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件玖绿,死亡現(xiàn)場離奇詭異,居然都是意外死亡叁巨,警方通過查閱死者的電腦和手機(jī)斑匪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锋勺,“玉大人蚀瘸,你說我怎么就攤上這事∈鳎” “怎么了贮勃?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長苏章。 經(jīng)常有香客問我寂嘉,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任垫释,我火速辦了婚禮丝格,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘棵譬。我一直安慰自己显蝌,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布订咸。 她就那樣靜靜地躺著曼尊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪脏嚷。 梳的紋絲不亂的頭發(fā)上骆撇,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天,我揣著相機(jī)與錄音父叙,去河邊找鬼神郊。 笑死,一個胖子當(dāng)著我的面吹牛趾唱,可吹牛的內(nèi)容都是我干的涌乳。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼甜癞,長吁一口氣:“原來是場噩夢啊……” “哼夕晓!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起悠咱,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蒸辆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后析既,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體躬贡,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年眼坏,在試婚紗的時候發(fā)現(xiàn)自己被綠了逗宜。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡空骚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出擂仍,到底是詐尸還是另有隱情囤屹,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布逢渔,位于F島的核電站肋坚,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜智厌,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一诲泌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧铣鹏,春花似錦敷扫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至合溺,卻和暖如春卒密,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背棠赛。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工哮奇, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人睛约。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓鼎俘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親痰腮。 傳聞我的和親對象是個殘疾皇子而芥,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容