Django REST framework simplejwt | 登入驗證使用 email 與 password

Leo Chiu
手寫筆記
Published in
7 min readNov 1, 2019

前言

如果你想要使用 Django REST framework(DRF) 與 JWT 快速實現一個能夠驗證使用者 email 與 password 的小型應用,在閱讀 DRF 官方文件時,官方推薦使用 🔗django-rest-framework-simplejwt 這個套件。

接著,你在跟著文件進行實作時感覺都沒有問題,可以很順利的 POST username 與 password 到後端,後端就會送一組 accessrefresh 的 JWT token 給你,一切感覺都很美好。但是,也許突然你會有疑問:

如果我想要用 email 與 password 驗證可以嗎 ?

答案是可以的,而且實作上非常簡單。

快速建立 Django 與 DRF 的環境

在這個範例中,我們使用的套件版本如下:

  • Django 2.2.6
  • Django REST framework 3.10.3
  • Django-rest-framework-simplejwt 4.3.0

安裝相依套件

首先,我們使用 pip 安裝相依套件,如果你不想讓弄髒環境,可以使用 virtualenv 隔離 Python 開發環境。

pip install django djangorestframework djangorestframework_simplejwt

建立 Django 環境

首先,我們先建立一個 django 的專案,專案名稱叫做 jwt-authentication。

django-admin startproject jwt-authentication

接著,則是用 Django 內建的 User 模組,建立一個使用者的帳號、信箱與密碼。別忘記在建立使用者以前要先 migrate

python manage.py migrate
python manage.py createsuperuser

建立 Djangor REST framework 環境

因為在這個範例中,我們沒有要撰寫 DRF 的程式碼,所以初始化非常簡單,只要在 INSTALLED_APPS 中引入 rest_framework 及可。

建立 Django REST framwork simplejwt 環境

以下參考 🔗 simplejwt github

在這個範例中,DEFAULT_AUTHENTICATION_CLASSES 要加也可以,不加也可以,因為只是要實現用 email 與 password 也可以獲得 JWT 的 token,與權限機制沒有關係。

最後,在 urls.py 中註冊獲取 JWT token 的 api。

我們使用瀏覽器測試 api ,POST 剛剛建立的 username 與 password,可以看到系統回傳了一組 accessrefresh

這時如果使用 email 與 password 獲取 JWT token 就會失敗,因為它原生要求的是輸入 username 與 password。

接下來,我們會對 Django 動一點手腳,讓 email 與 password 同樣可以獲得 JWT token。

修改 authentication backend 讓使用者可以用 email 與 password 進行驗證

當你想要修改驗證機制時,你會去看看 simplejtw 是不是有提供介面讓我們可以快速達成目的。

在網路上有些資料都會提到可以繼承 TokenObtainPairSerializer 這個類別,然後自訂義一個 custom serializer,修改驗證的方法。但是怕動到太多程式碼,所以後來跑去看了 TokenObtainPairSerializer 的原始碼,發現在這個類別中的 validate() 直接呼叫了父類別的 validate() 驗證方法。

https://github.com/davesque/django-rest-framework-simplejwt/blob/master/rest_framework_simplejwt/serializers.py#L65-L78

接著,繼續往前追原始碼, TokenObtainSerializer 中的 validate() 驗證方法呼叫了 Django 原生 User 模組的 authenticate() 方法。所以,尋找方法修改 authenticate() 也許可以解決我們的問題。

from django.contrib.auth import authenticate

https://github.com/davesque/django-rest-framework-simplejwt/blob/master/rest_framework_simplejwt/serializers.py#L43

後來,在這篇 🔗stackoverflow 的問答中,其中一個回應就有提到如何修改 Django 提供的 authentication 介面。

修改 authentication 介面

沒想到 Django 提供了 authentication 的介面,所以我們只要自訂一個客製化的類別,就可以讓程式同時搜尋資料庫中的 username 與 email 達到我們的目的。

我們在 jwt_authentication 中新增 backend.py,並在裡面定義客製化的類別:

settings.py 中修改 authentication 的介面變成我們寫的客製化類別:

使用 email 與 password 獲得 token

做完以上步驟後,再打開瀏覽器測試一次,終於,我們可以使用 email 與 password 成功獲得 token。

總結

在這篇文章中,我們使用的套件是官方推薦的 🔗simplejwt。simplejwt 使用的驗證方法是 Django 原生 User 模組的 authenticate(),所以換個方法,不是修改 TokenObtainPairSerializer 中的 validate(),而是嘗試改變 Django提供的 authentication 介面,讓使用 email 與 password 的驗證方法得以實現。

這個方式是非常快速且簡易的方法,使用這種方法,不論使用者輸入的是 username 還是 email,後端都可以在接收到資料後成功進行驗證並回傳 JWT token。

分享就到這邊,如果喜歡我的文章可以幫我拍個幾下手,在閱讀文章時如果有遇到什麼問題,或是有什麼建議,都歡迎留言告訴我,謝謝。 😃

Reference

--

--

Leo Chiu
手寫筆記

每天進步一點點,在終點遇見更好的自己。 Instragram 小帳:@leo.web.dev