Django中 JWT 簡單的 實現登陸驗證 -- obtain_jwt_token
首先先宣告以下本次進行登陸驗證操作的環境:
Django框架中,在專案名同名的檔案包下建立一個users子應用(正常流程下,咱們在註冊時,已經將這個子應用建立好了);具體的一些檔案可以參考下圖。
當前,在使用JWT之前,我相信大家應該知道把JWT安裝一下的吧
pip install djangorestframework-jwt
Django REST framework JWT提供了登入簽發JWT的檢視,可以直接使用;
也就是說,這個JWT已經把咱們需要進行登陸驗證的檢視給咱們寫好了,咱們現在只需要在urls中將檢視進行相關的註冊就可以了;
路由註冊
在 users/urls.py 中,將下面一段註冊路由的程式碼加入:
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
url(r'^authorizations/$', obtain_jwt_token),
]
咱們可以來看一下,這和obtain_jwt_token
檢視函式,時如何進行相關驗證的;(原始碼講解開始)
- 咱們先從
obtain_jwt_token
中進去看一下這個obtain_jwt_token是什麼樣的檢視函式,圖片如下:
- 然後,現在進入到
ObtainJSONWebToken
我們可以從原始碼中,看出以下幾個點:
- 這個檢視函式時繼承於
JSONWebTokenAPIView
- 這個檢視函式的註釋翻譯過來是:
使用使用者的使用者名稱和密碼接收POST的API檢視。
返回可用於經過身份驗證的請求的JSON Web令牌。
- 這個檢視函式所使用的序列化器是
JSONWebTokenSerializer
- 先看一下
JSONWebTokenAPIView
這個繼承的類檢視實現了什麼功能:
這裡我們主要是看def post
裡面具體實現的內容:
-
if serializer.is_valid():
- 首先是獲取user,token值,然後將進行
response_data = jwt_response_payload_handler(token, user, request)
的操作,我們再看一下這段程式碼的實現內容;
- 我們通過這個
from rest_framework_jwt.utils import jwt_response_payload_handler
獲取jwt_response_payload_handler
,如下:
def jwt_response_payload_handler(token, user=None, request=None):
"""
Returns the response data for both the login and refresh views.
Override to return a custom response such as including the
serialized representation of the User.
Example:
def jwt_response_payload_handler(token, user=None, request=None):
return {
'token': token,
'user': UserSerializer(user, context={'request': request}).data
}
翻譯:返回登入檢視和重新整理檢視的響應資料。
覆蓋以返回自定義響應,例如包括使用者的序列化表示。
例:
def jwt_response_payload_handler(token,user = None,request = None):
返回{
'token':token,
'user':UserSerializer(user,context = {'request':request})。data
}
"""
return {
'token': token
}
也就是說,這個jwt_response_payload_handler
就是處理響應資料,進行序列化返回的;
那麼我們的JSONWebTokenAPIView
就是在之前的Response基礎上,增加了token值得返回,當然,處理之後,還是會將response = Response(response_data)
,然後再返回這對於我們下面說的自定義jwt_response_payload_handler
,自定義我們需要進行返回的資料;
- 我們現在再看一下
JSONWebTokenSerializer
這個序列化器具體做了什麼;
- 首先看一下這個註釋:
Serializer類用於驗證使用者名稱和密碼。
'username’由自定義UserModel.USERNAME_FIELD標識。
返回可用於驗證以後呼叫的JSON Web令牌。
原來是用來驗證使用者名稱和密碼是否匹配的,那麼再看一下是如何驗證的;
- 首先, 在 __init__中,為這個序列化器定義了兩個欄位,也就是我們想要的使用者名稱和密碼欄位;
- 然後,在validate函式中,我們可以看到,首先是進行取值和判空處理,在使用者名稱和密碼都不為空的情況下,進行驗證
-
user = authenticate(**credentials)
這個是先進行解包,在進行authenticate的使用者名稱和密碼的驗證;
- 現在將Django自帶的authenticate的原始碼看一下:
關於authenticate的用法介紹,我在這裡擷取一段文字供參考:
也就是說,在進行authenticate驗證後,如果使用者名稱和密碼驗證通過的話,那麼就返回一個user物件,後期的login登陸的話,使用者的資料資訊就可以從這個物件裡面進行獲取並登陸了。
也就是說,如果我們需要進行更多的資訊需要驗證,那麼我們可以改寫這個authenticate
函式,當然,是需要繼承我們的ModelBackend
類;
自定義jwt認證成功返回資料
在users/utils.py中增加下面的程式碼;
def jwt_response_payload_handler(token, user=None, request=None):
return {
'token': token,
'user_id': user.id,
'username': user.username
}
在主檔案的settings.py中也是需要對配置資訊進行修改的:
JWT_AUTH = {
"""設定處理時使用的函式,就是上一步我們自己定義的那一個"""
'JWT_RESPONSE_PAYLOAD_HANDLER': 'users.utils.jwt_response_payload_handler',
}
自定義 多賬號驗證
def get_user_account(account):
"""根判斷使用者登陸的是使用者名稱還是手機號"""
try:
if re.match('^1[3-9]\d{9}$', account):
user = User.objects.get(mobile=account)
else:
user = User.objects.get(username=account)
except User.DoesNotExist:
raise None
return user
# 自定義Django的認證,滿足多賬號的登陸
class UsernameMobileAuthBackend(ModelBackend):
"""對使用者進行密碼身份的校驗"""
def authenticate(self, request, username=None, password=None, **kwargs):
user = get_user_account(username)
if not user and user.check_password(password):
"""如果使用者密碼校驗成功,返回使用者模型物件,當然了,如果使用者不存在,那麼就不用再返回None了,因為在呼叫函式的時候
就返回None"""
return user
我們改寫之後,還需要告訴Django,現在需要使用我們自定義的認證方法,我們就需要在settings.py中申明一下:
AUTHENTICATION_BACKENDS = [
'users.utils.UsernameMobileAuthBackend',
]