Backend-DRF-關於DRF認證機制源碼

更新於 發佈於 閱讀時間約 11 分鐘

本篇藉由追蹤DRF認證的源碼,幫助初學者能夠更佳理解其相關機制。

以下是簡單的Authentication寫法:

# setting.py 
# 全局認證設定

REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": ["authentication.auth.MyAuthentication"]
}


# authentication/auth.py

class MyAuthentication(BaseAuthentication):
def authenticate(self, request):
token = request.query_params.get('token')
# 假設request有帶token就給過
if token:
return ('user', token)
raise AuthenticationFailed({"code": "401", "message": "Unauthorized"})


# app/views.py
# 提供2個view

class UserView(APIView):
authentication_classes = []
def get(self, request):
print(request.user, request.auth)
return Response({'message': 'success'})


class LoginView(APIView):
def get(self, request):
print(request.user, request.auth)
return Response({'message': 'success'})


# 路由

urlpatterns = [
path('user/', UserView.as_view()),
path('login/', LoginView.as_view()),
]

從源碼分析,以上執行as_view()方法,將返回view作為路由的callback function,並在接收request時執行dispatch,透過反射到我們自定義類中的方法 (get, post, delete, put ...)

# as_view()返回view函式,view函式執行dispatch
def as_view(cls, **initkwargs):
def view(request, *args, **kwargs):
self = cls(**initkwargs)
self.setup(request, *args, **kwargs)
if not hasattr(self, "request"):
raise AttributeError(
"%s instance has no 'request' attribute. Did you override "
"setup() and forget to call super()?" % cls.__name__
)
return self.dispatch(request, *args, **kwargs)
return view


def dispatch(self, request, *args, **kwargs):
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?

try:
self.initial(request, *args, **kwargs)

if 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_allowed
response = handler(request, *args, **kwargs)

從上可以觀察到DRF有針對Django的request再進行封裝:

request = self.initialize_request(request, *args, **kwargs)
self.request = request


# 增加 authenticators
def initialize_request(self, request, *args, **kwargs):
return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)

# authenticators的內容​
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
def get_authenticators(self):
return [auth() for auth in self.authentication_classes]

APIView下的 authentication_classes 是api_settings.DEFAULT_AUTHENTICATION_CLASSES,也就是我們一開始在settings.py設定的位置。而如果像我們在自定義類UserView中有設定authentication_classes = [],依繼承規則會優先去使用。

在dispatch中會使用initial,其內最終就會用到request.user,還記得我前一篇文章嗎?

self.initial(request, *args, **kwargs)


# initail 內有 perform_authentication (其他程式碼省略)
def initial(self, request, *args, **kwargs):
self.perform_authentication(request)


# 使用到 request.user​
def perform_authentication(self, request):
request.user

至於request.user是在哪裡給值的呢?我們再觀察一下源碼,[auth() for auth in self.authentication_classes] 中會分別取authentication_classes內的類並實例化成對象:

def get_authenticators(self):
return [auth() for auth in self.authentication_classes]

在Request類的源碼,會依次嘗試每個認證器進行認證,直到有一個成功,或者所有認證器都失敗

# 一開始沒有_user,故執行self._authenticate()
@property
def user(self):
if not hasattr(self, '_user'):
with wrap_attributeerrors():
self._authenticate()

return self._user

# ​user_auth_tuple 為我們定義認證類成功的返回值 ('user', token)
def _authenticate(self):
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()

依然承接前篇文章,若認證失敗或沒設定認證器,則會進入_not_authenticated。

如果在純淨版把一些app拿掉,沒有給UNAUTHENTICATED_USER,這邊就會造成報錯了。

def _not_authenticated(self):
self._authenticator = None
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

以上為DRF認證機制的源碼解析,希望你們會喜歡!

一位離開半導體業的資料科學家, 在全端掙扎的日誌
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
對於想透過DRF來建立RESTfull API的初學者,建立純淨版的項目將有助於了解 DRF 的核心概念,並適合在簡單應用中快速搭建 RESTful API。
對於想透過DRF來建立RESTfull API的初學者,建立純淨版的項目將有助於了解 DRF 的核心概念,並適合在簡單應用中快速搭建 RESTful API。
你可能也想看
Google News 追蹤
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
※ 原本狀態:伺服器渲染 這是 MVC 架構下的 request / response 示意圖,在這張圖呈現的架構裡,畫面和資料都由同一個架構處理。 伺服器渲染流程: 瀏覽器針對特定網址送出請求。 路由器解析請求後,轉接給對應的 controller。 controller 按照要求,透過
Thumbnail
在前一篇我們已經成功地建立簽核表單及簽核節點並關聯回請假表單,而本篇會接著介紹如何管理簽核節點狀態並同步更新簽核表單狀態。
Thumbnail
本文介紹瞭如何在後端系統開發時設計不同表單的簽核流程,包括請假表單和採購表單。以及如何動態生成簽核表單,並建立簽核節點。另外還介紹瞭如何利用繼承來簡化簽核流程的設定。
本篇文章將介紹如何使用Lambda建立Pre-Sign URL 的簡單範例,讓讀者瞭解如何自行發揮。
Thumbnail
學習如何使用Python連接MongoDB進行憑證監控,包括建立MongoDB docker-compose、連接MongoDB、讀取yaml並寫入MongoDB、傳入env以及domain寫入MongoDB、讀取MongoDB、修改MongoDB、刪除MongoDB。
Thumbnail
軟體系統的發展歷程大多相似,首重解決基本需求、提供操作介面,進而提升安全性、擴充功能、優化操作。
Thumbnail
本文介紹了 Django 專案中各個檔案的用途,包括 settings.py、tests.py、models.py 等。並且解釋了 MTV 架構的後端運作流程,以及相對應的範例介紹。閱讀本文可幫助讀者更好地瞭解 Django 後端開發。
Thumbnail
授權碼模式連線流程 用戶端請求自己的伺服器。 伺服器發現用戶沒登入,就導向認證伺服器。 認證伺服器顯示授權頁面,等待用戶授權。 用戶確認授權後,授權頁面會向認證伺服器請求授權碼。 用戶獲取授權碼。 用戶將授權碼傳給伺服器。 伺服器拿授權碼向認證伺服器取得token。 應用註冊
今天就讓我們依照前一天的情境題,來撰寫測試案例函數吧! 這次同樣地,先讓我們規畫擬訂測試案例: 測試案例 使用者註冊: 使用者可送出註冊資料,系統將建立使用者資料,並送出含有專屬驗證連結之驗證信,當此驗證連結被開啟後,將讓使用者轉為已驗證狀態 請求錯誤的驗證連結: 錯誤的驗證連結被開啟後
前兩天,我們探討了「網站文章」的情境題;今明兩天,就讓我們探討另一個情境題「會員註冊」吧! 這邊我們同樣假設網站是採前後端分離的設計,因此我們就專注在測試 API 的部分,不過會多一個「註冊驗證信」的部分要實作與做測試驗證。 使用案例 使用者可填寫註冊資料後送出資料。 使用者可收到註冊驗證信
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
※ 原本狀態:伺服器渲染 這是 MVC 架構下的 request / response 示意圖,在這張圖呈現的架構裡,畫面和資料都由同一個架構處理。 伺服器渲染流程: 瀏覽器針對特定網址送出請求。 路由器解析請求後,轉接給對應的 controller。 controller 按照要求,透過
Thumbnail
在前一篇我們已經成功地建立簽核表單及簽核節點並關聯回請假表單,而本篇會接著介紹如何管理簽核節點狀態並同步更新簽核表單狀態。
Thumbnail
本文介紹瞭如何在後端系統開發時設計不同表單的簽核流程,包括請假表單和採購表單。以及如何動態生成簽核表單,並建立簽核節點。另外還介紹瞭如何利用繼承來簡化簽核流程的設定。
本篇文章將介紹如何使用Lambda建立Pre-Sign URL 的簡單範例,讓讀者瞭解如何自行發揮。
Thumbnail
學習如何使用Python連接MongoDB進行憑證監控,包括建立MongoDB docker-compose、連接MongoDB、讀取yaml並寫入MongoDB、傳入env以及domain寫入MongoDB、讀取MongoDB、修改MongoDB、刪除MongoDB。
Thumbnail
軟體系統的發展歷程大多相似,首重解決基本需求、提供操作介面,進而提升安全性、擴充功能、優化操作。
Thumbnail
本文介紹了 Django 專案中各個檔案的用途,包括 settings.py、tests.py、models.py 等。並且解釋了 MTV 架構的後端運作流程,以及相對應的範例介紹。閱讀本文可幫助讀者更好地瞭解 Django 後端開發。
Thumbnail
授權碼模式連線流程 用戶端請求自己的伺服器。 伺服器發現用戶沒登入,就導向認證伺服器。 認證伺服器顯示授權頁面,等待用戶授權。 用戶確認授權後,授權頁面會向認證伺服器請求授權碼。 用戶獲取授權碼。 用戶將授權碼傳給伺服器。 伺服器拿授權碼向認證伺服器取得token。 應用註冊
今天就讓我們依照前一天的情境題,來撰寫測試案例函數吧! 這次同樣地,先讓我們規畫擬訂測試案例: 測試案例 使用者註冊: 使用者可送出註冊資料,系統將建立使用者資料,並送出含有專屬驗證連結之驗證信,當此驗證連結被開啟後,將讓使用者轉為已驗證狀態 請求錯誤的驗證連結: 錯誤的驗證連結被開啟後
前兩天,我們探討了「網站文章」的情境題;今明兩天,就讓我們探討另一個情境題「會員註冊」吧! 這邊我們同樣假設網站是採前後端分離的設計,因此我們就專注在測試 API 的部分,不過會多一個「註冊驗證信」的部分要實作與做測試驗證。 使用案例 使用者可填寫註冊資料後送出資料。 使用者可收到註冊驗證信