單獨看用法
你定義了一個類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)行驗證想鹰。
梳理
梳理
:
- 創(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,
}
- 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')