Django中 JWT -- obtain_jwt_token的原理

为什么使用JWT

在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证。我们不再使用Session认证机制,而使用Json Web Token认证机制。

安装

首先先声明以下本次进行登陆验证操作的环境:
Django框架中,在项目名同名的文件包下创建一个users子应用(正常流程下,咱们在注册时,已经将这个子应用创建好了);具体的一些文件可以参考下图。
当前,在使用JWT之前,我相信大家应该知道把JWT安装一下的吧

pip install djangorestframework-jwt

Django中 JWT -- obtain_jwt_token的原理_第1张图片


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 这个视图函数中;
    我们可以从源码中,看出以下几个点:
    Django中 JWT -- obtain_jwt_token的原理_第2张图片
  • 这个视图函数时继承于 JSONWebTokenAPIView
  • 这个视图函数的注释翻译过来是:

使用用户的用户名和密码接收POST的API视图。
返回可用于经过身份验证的请求的JSON Web令牌。

  • 这个视图函数所使用的序列化器是 JSONWebTokenSerializer
  1. 先看一下JSONWebTokenAPIView 这个继承的类视图实现了什么功能:
    这里我们主要是看def post 里面具体实现的内容:
  • if serializer.is_valid(): 这个是在序列化器的验证完成并返回True的情况下可以进行下面的操作,这个验证我们下面后续会讲解;

Django中 JWT -- obtain_jwt_token的原理_第3张图片

  • 首先是获取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,如下:

Django中 JWT -- obtain_jwt_token的原理_第4张图片

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令牌。

Django中 JWT -- obtain_jwt_token的原理_第5张图片

原来是用来验证用户名和密码是否匹配的,那么再看一下是如何验证的;

  • 首先, 在 __init__中,为这个序列化器定义了两个字段,也就是我们想要的用户名和密码字段;
  • 然后,在validate函数中,我们可以看到,首先是进行取值和判空处理,在用户名和密码都不为空的情况下,进行验证
  • user = authenticate(**credentials) 这个是先进行解包,在进行authenticate的用户名和密码的验证;

Django中 JWT -- obtain_jwt_token的原理_第6张图片

  • 现在将Django自带的authenticate的源代码看一下:
    Django中 JWT -- obtain_jwt_token的原理_第7张图片

关于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',
]

你可能感兴趣的:(Django扩展,JWT)