1. 程式人生 > >Django中 JWT 簡單的 實現登陸驗證 -- obtain_jwt_token

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 檢視函式,時如何進行相關驗證的;(原始碼講解開始)

  1. 咱們先從obtain_jwt_token中進去看一下這個obtain_jwt_token是什麼樣的檢視函式,圖片如下:
    在這裡插入圖片描述
  2. 然後,現在進入到ObtainJSONWebToken
    這個檢視函式中;
    我們可以從原始碼中,看出以下幾個點:
  • 這個檢視函式時繼承於 JSONWebTokenAPIView
  • 這個檢視函式的註釋翻譯過來是:

使用使用者的使用者名稱和密碼接收POST的API檢視。
返回可用於經過身份驗證的請求的JSON Web令牌。

  • 這個檢視函式所使用的序列化器是 JSONWebTokenSerializer

在這裡插入圖片描述

  1. 先看一下JSONWebTokenAPIView 這個繼承的類檢視實現了什麼功能:
    這裡我們主要是看def post 裡面具體實現的內容:
  • if serializer.is_valid():
    這個是在序列化器的驗證完成並返回True的情況下可以進行下面的操作,這個驗證我們下面後續會講解;

在這裡插入圖片描述

  • 首先是獲取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 ,自定義我們需要進行返回的資料;

  1. 我們現在再看一下 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',
]