ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

jwt内置签发方法修改返回格式 drf_jwt签发认证源码 自定义用户表签发token

2021-09-10 12:33:19  阅读:245  来源: 互联网

标签:username 自定义 签发 jwt token user import payload


JWT内置签发方法修改返回格式

JWT的内置签发方法只会返回一个token串,但大部分情况,我们是需要返回用户名或者其他的一些信息,这时候我们就需要针对返回格式做出一些修改:

在url.py中配置好内置的登录路由:

from django.contrib import admin
from django.urls import path
from rest_framework_jwt.views import obtain_jwt_token

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', obtain_jwt_token),
]

创建一个py文件写一个函数,utils.py:

'''
这里的函数名字不是固定的可以随意取
但是传的参数是固定的
后面return什么,前端就会显示什么
'''

def jwt_response_payload_handler(token, user, request):
    return {
        'token': token,
        'username': user.username
    }

在settings.py文件里将这个函数配置进JWT_AUTH里面:

# drf_jwt的认证配置(drf_jwt有个默认配置文件)

JWT_AUTH = {
    'JWT_RESPONSE_PAYLOAD_HANDLER': 'app01.utils.jwt_response_payload_handler'
}

这样配置完成之后就可以在返回信息中显示用户名了:

image

drf_jwt签发的源码分析

由路由的obtain_jwt_token>ObtainJSONWebToken(JSONWebTokenAPIView)>视图类ObtainJSONWebToken(JSONWebTokenAPIView)

image

可以看到我们urls.py中配置的路由obtain_jwt_token其实就是一个视图类:

image

我们再来看看这个视图类,发现视图类只有一行代码,一个序列化类,但是我们明明发的是post请求,这个视图里面却没有post方法,那肯定在父类里面:

image

进入到父类这里可以看到这个视图类帮我们做了处理,因为这本来就是一个登录的视图类,就不该有权限和认证,所有放了两个空元组:

image

JSONWebTokenAPIView内有个post方法,重点开始了,它将request.data进行序列化,得到序列化对象,然后对这个序列化对象进行了校验,会执行字段自己的校验规则,局部钩子,全局钩子。

image

其实这里的序列化类就是一开始我们看到的序列化类JSONWebTokenSerializer:

image

那我们来看一下这个JSONWebTokenSerializer序列化类:

image

看完__ init __之后来到了我们做重要的validate:

image

执行完validate之后,我们又需要返回到.isvalid看看之后是怎么处理的:

image

drf_jwt认证token源码

读JSONWebTokenAuthentication的父类BaseJSONWebTokenAuthentication的authenticate

image

进入到authenticate方法,这一句其实就是取出了Authorization的value值:

image

那么它是怎么去取的呢,我们需要回到它的子类JSONWebTokenAuthentication,看get_jwt_value方法:

image

image

所以从get_authorization_header就可以知道get_jwt_value的意思了:

image

这就是authenticate第一句的意思,它将token取了出来,让我们再来看看authenticate:

image

image

自定义用户表签发token

使用自定义的表签发token,既然是自己写的,那很多东西都可以自己来定义,比如我们可以不使用权限类。

views.py

from rest_framework.views import APIView
from app01.models import UserInfo
from rest_framework_jwt.settings import api_settings
from rest_framework.response import Response

# 从 rest_framework_jwt.settings.api_settings中导入生成token方法
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER


class LoginView(APIView):
    def post(self, request):
        username = request.data.get('username')
        password = request.data.get('password')
        user = UserInfo.objects.filter(username=username, password=password).first()
        if user:  # 如果用户名密码正确签发token

            # 将用户信息转码成payload
            payload = jwt_payload_handler(user)

            # 将payload加上header和signature生成token
            token = jwt_encode_handler(payload)
            return Response({
                'code': '200',
                'msg': '登录成功',
                'token': token,
                'username': username
            })
        else:
            return Response({'code': '101', 'msg': '用户名或密码错误'})

urls.py中配置

from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.LoginView.as_view())
]

自定义用户表的认证类

创建auth.py定义自己的认证类

# 使用自己的认证类来认证token
import jwt
from rest_framework import exceptions
from rest_framework_jwt.authentication import BaseAuthentication
from rest_framework_jwt.settings import api_settings
from app01.models import UserInfo

jwt_decode_handler = api_settings.JWT_DECODE_HANDLER


class JwtAuthentication(BaseAuthentication):
    def authenticate(self, request):
        # 取出前端传入的token
        token = request.META.get('HTTP_TOKEN')
        # 通过token获取payload
        try:
            payload = jwt_decode_handler(token)
        except jwt.ExpiredSignatureError:
            msg = '签名过期'
            raise exceptions.AuthenticationFailed(msg)
        except jwt.DecodeError:
            msg = '解码错误'
            raise exceptions.AuthenticationFailed(msg)
        except jwt.InvalidTokenError:
            raise exceptions.AuthenticationFailed()

        # 查库获取到user对象
        # user = UserInfo.objects.filter(pk=payload['user_id']).first()

        """
        可以针对查库做优化,如果不是必要可以直接从token的payload中去取,不用每次都查库
        但是也有弊端,就是只能获取到user_id和username
        """

        # 优化方式一:
        # user = UserInfo(id=payload['user_id'], username=payload['username'])
        # 优化方式二:
        user = {'id': payload['user_id'], 'username': payload['username']}

        # 返回当前用户
        return user, token

将该认证类配置在视图类BookView当中:

from app01.models import Book
from app01.serializer import BookSerializer
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin
from app01.auth import JwtAuthentication


class BookView(ListModelMixin, GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    authentication_classes = [JwtAuthentication]

    def get(self, request):
        return self.list(request)

这样便完成了自定义类。

标签:username,自定义,签发,jwt,token,user,import,payload
来源: https://www.cnblogs.com/wuzhixian/p/15250841.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有