drf-router和authenticate認(rèn)證源碼分析
一、路由Routers
在 Rest Framework 中提供了兩個(gè) router , 可以幫助我們快速的實(shí)現(xiàn)路由的自動(dòng)生成。
必須是繼承 ModelViewSet 的視圖類才能自動(dòng)生成路由
SimpleRouter
使用方法:
urls.py
# 第一步:導(dǎo)入routers模塊
from rest_framework import routers
# 第二步:實(shí)例化得到對(duì)象
router = routers.SimpleRouter()
# 第三步:注冊( register('前綴', viewset視圖集, 路由的別名) )
router.register('books', views.BooksViewset)
# 第四步:生成路由加入到原路由中
# 方式一:
urlpatterns = [
...
]
urlpatterns += router.urls
# 方式二:
urlpatterns = [
...
url(r'^', include(router.urls))
]
# 形成路由如下
<URLPattern '^books/$' [name='books-list']>
<URLPattern '^books/(?P<pk>[^/.]+)/$' [name='books-detail']>
DefaultRouter
DefaultRouter與SimpleRouter的區(qū)別是,DefaultRouter會(huì)多附帶一個(gè)默認(rèn)的API根視圖,返回一個(gè)包含所有列表視圖的超鏈接響應(yīng)數(shù)據(jù)。
# 前兩條和SimpleRouter一樣 <URLPattern '^books/$' [name='books-list']> <URLPattern '^books/(?P<pk>[^/.]+)/$' [name='books-detail']> # 效果也和前兩條類似, # 如:http://127.0.0.1:8000/books.json <URLPattern '^books\.(?P<format>[a-z0-9]+)/?$' [name='books-list']> # http://127.0.0.1:8000/books/1.json <URLPattern '^books/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$' [name='books-detail']> # 多了個(gè)根路由http://127.0.0.1:8000/ <URLPattern '^$' [name='api-root']>, <URLPattern '^\.(?P<format>[a-z0-9]+)/?$' [name='api-root']>
action的使用
action是為了給繼承自 ModelViewSet 的視圖類中自定義的函數(shù)也添加路由
例如下面這樣:
from rest_framework.viewsets import ModelViewSet
from rest_framework.response import Response
from app01.ser import BooksSerializers
from app01.models import Books
class BooksViewSet(ModelViewSet):
queryset = Books.objects.all()
serializer_class = BooksSerializers
# 這種方法不會(huì)自動(dòng)生成,需要用action配置
def get_num(self, request, pk):
book = self.get_queryset()[:int(pk)]
ser = self.get_serializer(book, many=True)
return Response(ser.data)
使用示例:
action是一個(gè)裝飾器,放在被裝飾的函數(shù)上方,
method:請(qǐng)求方式
detail:是否帶pk ——>True 表示路徑格式是xxx/<pk>/action方法名/——False 表示路徑格式是xxx/action方法名/
from rest_framework.viewsets import ModelViewSet
from rest_framework.response import Response
from rest_framework.decorators import action
from app01.ser import BooksSerializers
from app01.models import Books
class BooksViewSet(ModelViewSet):
queryset = Books.objects.all()
serializer_class = BooksSerializers
@action(methods=['GET', 'POST'], detail=True)
def get_num(self, request, pk):
book = self.get_queryset()[:int(pk)] # 獲取前幾條數(shù)據(jù)
ser = self.get_serializer(book, many=True)
return Response(ser.data)
# 生成路由如下
http://127.0.0.1:8000/books/2/get_num/
<URLPattern '^books/(?P<pk>[^/.]+)/get_num/$' [name='books-get-num']>
二、認(rèn)證
認(rèn)證的寫法
- 寫一個(gè)認(rèn)證類,繼承 BaseAuthentication,重寫 authenticate, 認(rèn)證的邏輯寫在里面,認(rèn)證通過,返回兩個(gè)值,一個(gè)值給Request對(duì)象的user, 認(rèn)證失敗,拋異常:APIException或者AuthenticationFailed
- 將認(rèn)證類添加到需要認(rèn)證視圖類的
authentication_classes = [認(rèn)證類1]中 - 全局使用,還是局部使用
# 全局使用,在setting.py中配置
REST_FRAMEWORK={
"DEFAULT_AUTHENTICATION_CLASSES":["app01.app_auth.MyAuthentication",]
}
# 局部使用,在視圖類上寫
authentication_classes=[MyAuthentication]
# 局部禁用
authentication_classes=[]
認(rèn)證源碼分析
1、APIView重寫as_view方法使之沒有csrf認(rèn)證——>但還是正常執(zhí)行 dispatch 方法,但是 dispatch方法被 APIView重寫了——>dispatch 中執(zhí)行了 self.initial 認(rèn)證方法——>有認(rèn)證,權(quán)限,頻率
2、現(xiàn)在只是看認(rèn)證源碼self.perform_authentication(request)
3、但是self.perform_authentication(request)就一句話:request.user,那么就需要去 drf 的 Request 對(duì)象中找 user 屬性(方法)
@property
def user(self):
# 先去判斷當(dāng)前對(duì)象中有沒有'_user'這個(gè)屬性,一開始肯定是沒有的,因?yàn)橛脩羰菦]有登錄的
if not hasattr(self, '_user'):
with wrap_attributeerrors():
# 沒有用戶,認(rèn)證出用戶
self._authenticate()
# 有用戶,直接返回用戶
return self._user
4、Request 類中的 user 方法,剛開始來,沒有_user,走 self._authenticate()
5、核心,就是Request類中的 _authenticate(self)
def _authenticate(self):
# 遍歷拿到一個(gè)認(rèn)證器,進(jìn)行認(rèn)證
# self.authenticators 配置的一堆認(rèn)證類產(chǎn)生的認(rèn)證類對(duì)象組成的 list
# self.authenticators 就是在視圖類中配置的:authentication_classes = [認(rèn)證類1,認(rèn)證類2] 的一個(gè)個(gè)認(rèn)證類的對(duì)象:
————>self.authenticators ==》 [認(rèn)證類1對(duì)象,認(rèn)證類2對(duì)象]
for authenticator in self.authenticators:
try:
# 認(rèn)證器調(diào)用認(rèn)證方法authenticate(認(rèn)證類對(duì)象self,request對(duì)象)
"""
def authenticate(self, request):
return (self.force_user, self.force_token)
"""
# 返回值:登錄的用戶與認(rèn)證的信息組成的 tuple
# 并且該方法被try包裹,就代表該方法會(huì)拋異常,拋異常就代表認(rèn)證失敗
user_auth_tuple = authenticator.authenticate(self) # self是request對(duì)象
except exceptions.APIException:
self._not_authenticated()
raise
# 返回值的處理
if user_auth_tuple is not None:
self._authenticator = authenticator
# 如果有返回值,就將 "登錄用戶" 與 "登錄認(rèn)證" 分別保存到 request.user / request.auth
self.user, self.auth = user_auth_tuple
return
# 如果返回值user_auth_tuple為空,代表認(rèn)證通過,但是沒有 "登錄用戶" 與 "登錄認(rèn)證信息",代表游客
self._not_authenticated()
認(rèn)證組件的使用
1、寫一個(gè)認(rèn)證類,繼承 BaseAuthentication,重寫 authenticate
# app01_auth.py
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from app01.models import UserToken
class TokenAuthentication(BaseAuthentication):
def authenticate(self, request):
# 認(rèn)證邏輯,如果認(rèn)證通過,返回兩個(gè)值
# 如果認(rèn)證失敗,拋出AuthenticationFailed異常
token = request.data.get('token')
if token:
user_token = UserToken.objects.filter(token=token).first()
# 認(rèn)證通過
if user_token:
return UserToken.user, token
else:
raise AuthenticationFailed('認(rèn)證失敗')
else:
raise AuthenticationFailed('請(qǐng)求地址中需要帶token')
2、將認(rèn)證類添加到需要認(rèn)證視圖類的authentication_classes = [認(rèn)證類1]中
# views.py
from rest_framework.viewsets import ModelViewSet
from rest_framework.views import APIView
from rest_framework.response import Response
from app01.models import Books, UserInfo, UserToken
from app01.ser import BooksSerializer
from app01.app01_auth import TokenAuthentication
import uuid
# 查看Books需要經(jīng)過認(rèn)證才能查看
class BooksView(ModelViewSet):
authentication_classes = [TokenAuthentication]
queryset = Books.objects.all()
serializer_class = BooksSerializer
# 登錄視圖,登錄后獲得token,后續(xù)用token認(rèn)證
class LoginView(APIView):
def post(self, request):
response_msg = {'status': 200, 'msg': ''}
username = request.data.get('username')
password = request.data.get('password')
user_obj = UserInfo.objects.filter(username=username, password=password).first()
if user_obj:
# 登錄成功生成一個(gè)隨機(jī)字符串
token = uuid.uuid4()
# 存到UserToken表中,update_or_create有就更新,沒有就新增
UserToken.objects.update_or_create(defaults={'token': token}, user=user_obj)
response_msg['msg'] = '登錄成功'
response_msg['token'] = token
else:
response_msg['msg'] = '賬戶或密碼錯(cuò)誤'
response_msg['status'] = 204
return Response(response_msg)
到此這篇關(guān)于drf-router和authenticate認(rèn)證源碼分析的文章就介紹到這了,更多相關(guān)drf-router和authenticate內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python文件名匹配與文件復(fù)制的實(shí)現(xiàn)
這篇文章主要介紹了Python文件名匹配與文件復(fù)制的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-12-12
Python數(shù)據(jù)結(jié)構(gòu)鏈表操作從基礎(chǔ)到高級(jí)實(shí)例深究
鏈表是一種基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu),它由一系列節(jié)點(diǎn)組成,每個(gè)節(jié)點(diǎn)都包含數(shù)據(jù)和指向下一個(gè)節(jié)點(diǎn)的引用,在Python中,可以使用類來實(shí)現(xiàn)鏈表,本文將介紹如何實(shí)現(xiàn)鏈表,并提供一些豐富的示例代碼來幫助你更好地理解其原理和應(yīng)用2023-12-12
Python使用eel模塊創(chuàng)建GUI應(yīng)用程序
在Python中,有許多庫和模塊可以用來創(chuàng)建圖形用戶界面(GUI)應(yīng)用程序,其中一個(gè)流行的選擇是使用eel模塊,下面小編就來為大家詳細(xì)介紹一下如何使用eel模塊創(chuàng)建GUI應(yīng)用程序吧2023-12-12
Windows上使用Python增加或刪除權(quán)限的方法
下面小編就為大家分享一篇Windows上使用Python增加或刪除權(quán)限的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-04-04
Django利用AJAX技術(shù)實(shí)現(xiàn)博文實(shí)時(shí)搜索
這篇文章主要介紹了Django如何利用AJAX技術(shù)實(shí)現(xiàn)博文實(shí)時(shí)搜索,幫助大家更好的理解和學(xué)習(xí)使用Django框架,感興趣的朋友可以了解下2021-05-05
python淺析守護(hù)線程與非守護(hù)線程的區(qū)別與使用
守護(hù)線程,又稱后臺(tái)線程,它是在后臺(tái)運(yùn)行的,如果所有前臺(tái)線程都死亡,那么后臺(tái)線程就會(huì)自動(dòng)死亡,本章我們來了解守護(hù)線程與非守護(hù)線程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-08-08
使用Python將xmind腦圖轉(zhuǎn)成excel用例的實(shí)現(xiàn)代碼(一)
這篇文章主要介紹了使用Python將xmind腦圖轉(zhuǎn)成excel用例的實(shí)現(xiàn)代碼(一),本文給大家介紹的非常詳細(xì)對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10

