首页 > 技术文章 > 九、drf_JWT认证

borntodie 2021-01-26 15:56 原文

drf_JWT认证

一、jwt实现过程

1. 构建jwt过程

①、用户提交用户名和密码给服务端,若果登录成功,使用jwt创建一个token串,并返回给用户

eyJ0eXAiOiJqd3QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6InpjYyIsImV4cCI6MTU5NDczODg5MX0.OCG4mUhs_yXIkxtxvG9MWJWjpbvnSGDcqMVtpsn_0mo

②、构建三段字符串之间的关系

  • 第一段字符串headers:内部包含了算法和token类型

    # 流程:先将python类型对象转换成json格式字符串,然后做base64加密
    # 内容
        headers = {
            'typ': 'jwt',
            'alg': 'HS256',
        } 
    
  • 第二段字符串payload:自定义的值

    # 流程:先将python类型对象转换成json个还是字符串,然后做base64加密
    # 内容(可自定义内容)
         payload = {
            'user_id': user.pk,
            'username': username,
            'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=300),  # 超时时间
        } 
    
  • 第三段字符串signature:将前两段串进行加密

    # 第一步:把1,2部分base64加密过后的结果进行拼接加密
    # 第二步:对前2部分的加密结果进行hs256加密 + 加盐
    # 第三步:对hs256加密后的密文在进行base64url加密再拼接到前1, 2部分base64格式的末尾作为sign.
    

③、以后用户访问时,需要携带token,后端需要对token进行校验

2. 检验jwt过程

①、获取前端传过来的token

token = request.META.get('HTTP_AUTHORIZATION')

token:eyJ0eXAiOiJqd3QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6InpjYyIsImV4cCI6MTU5NDczODg5MX0.OCG4mUhs_yXIkxtxvG9MWJWjpbvnSGDcqMVtpsn_0mo

②、对token进行切割,获取第二段内容进行base64解密,获取payload信息,检查是否超时

# 获得payload串  
payload = jwt_decode_handler(token) 
# 格式:{'user_id': 1, 'username': 'jason', 'exp': 1611321013, 'email': '3@qq.com'}

③、由于第三部分的字符串不能反解,把第一和第二段在进行hs256加密

1. 把1,2部分base64的密文拼接加密
2. 对前2部分加密进行hs256加密+加盐得到密文
3. 再将密文机进行base64加密, 与前两段的base64d格式的密文进行对比, 如果相等,表示token没有修改通过.

二、drf-jwt安装

1. 官网:http://getblimp.github.io/django-rest-framework-jwt/

2. 安装:pip install djangorestframework-jwt

三、使用内置jwt认证+token签发

1. 快速使用

# 路由中配置
from rest_framework_jwt.views import ObtainJSONWebToken,VerifyJSONWebToken,RefreshJSONWebToken,obtain_jwt_token

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/', ObtainJSONWebToken.as_view()),
    # url(r'^login/', obtain_jwt_token), 和上面的效果一样,
]
  • 解析:为什么路由中配置了obtain_jwt_token用户认证, 签发token等等都不需要写了?

    # jwt中的views视图类
    class JSONWebTokenAPIView(APIView): # 基类,继承了APIView
    	pass
    
    class ObtainJSONWebToken(JSONWebTokenAPIView): # 子类,继承JSONWebTokenAPIView
        # JSONWebTokenSerializer内部就在序列换器里面使用validate钩子, 实现了token的签发
        serializer_class = JSONWebTokenSerializer
    
    class VerifyJSONWebToken(JSONWebTokenAPIView): # 子类,继承JSONWebTokenAPIView
        pass
    
    class RefreshJSONWebToken(JSONWebTokenAPIView): # 子类,继承JSONWebTokenAPIView
        pass
    
    # 重点
    # 看继承关系: obtain_jwt_token = ObtainJSONWebToken.as_view() -> ObtainJSONWebToken -> JSONWebTokenAPIView
    # JSONWebTokenAPIView就是我们的视图类. 它里面写了post方法, 处理我们的认证请求.
    
    obtain_jwt_token = ObtainJSONWebToken.as_view()
    refresh_jwt_token = RefreshJSONWebToken.as_view()
    verify_jwt_token = VerifyJSONWebToken.as_view()
    

2. 使用内置认证快速实现引发的三大缺陷及解决.

①、缺陷1:jwt提供的视图中is_valid校验成功时,无法自定义返回数据格式

  • 措施:需要自定义response函数,用来覆盖jwt默认的response函数

    # utils.py自定义认证成功返回数据格式
    def my_jwt_response_payload_handler(token, user=None, request=None):
        return {
            'token': token,
            'msg':'登录成功',
            'status':100,
            'username':user.username
        }
    # settings.py配置文件
    JWT_AUTH = {
      'JWT_RESPONSE_PAYLOAD_HANDLER':'api.utils.my_jwt_response_payload_handler'
    }
    

②、缺陷2:jwt提供的视图中is_valid校验失败时,无法自定义返回数据格式

  • 措施:新建视图类,继承ObtainJSONWebToken,重写post方法,使用super拿到response对象,判断是否携带token这个key,有返回成功的response,无,返回失败response

    # 路由代码
    urlpatterns = [
        path('login/', CustomObtainJSONWebToken.as_view()),
    ]
    
    # 视图代码:
    from rest_framework_jwt.views import ObtainJSONWebToken
    
    class CustomObtainJSONWebToken(ObtainJSONWebToken):
        def post(self, request, *args, **kwargs):
            response = super().post(request, *args, **kwargs)
            # 有token表示用户登录认证成功, 返回正确的response. 没有token表示认证失败, 返回错误的response.
            if response.data.get('token'):
                obj = CommonResponse(messages='登陆成功', results=response.data)
            else:
                obj = CommonResponse(messages='登录失败', results=response.data)
            return obj
    

③、缺陷3:jwt提供的认证签发token机制无法实现用户多方式登录

  • 措施:新建类基础jwt提供的JSONWebTokenSerializer序列化类, 重写validate方法, 实现用户多方式登录签发token.(基于pyjwt模块)

    # 路由代码:
    from rest_framework_jwt.views import ObtainJSONWebToken, obtain_jwt_token, JSONWebTokenAPIView, VerifyJSONWebToken
    # import user.views as views
    from user.views import CustomObtainJSONWebToken
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('api/', include('user.urls')),
        path('login_jwt/', ObtainJSONWebToken.as_view()),
        path('login_custom/', CustomObtainJSONWebToken.as_view()),
        path('login_custom/', CustomObtainJSONWebToken.as_view()),
        # path(r'xadmin/', xadmin.site.urls)
    ]
    
    # 视图代码:
    from rest_framework_jwt.views import ObtainJSONWebToken
    from .ser import CostomJSONWebTokenSerializer
    
    
    class CustomObtainJSONWebToken(ObtainJSONWebToken):
        serializer_class = CostomJSONWebTokenSerializer
    
        def post(self, request, *args, **kwargs):
            response = super().post(request, *args, **kwargs)
            # 有token表示用户登录认证成功, 返回正确的response. 没有token表示认证失败, 返回错误的response.
            if response.data.get('token'):
                obj = CommonResponse(messages='登陆成功', results=response.data)
            else:
                obj = CommonResponse(code=2000, messages='登录失败', results=response.data)
            return obj
    
    # 序列化器代码:
    import re
    import jwt
    import datetime
    from django.conf import settings
    from rest_framework.exceptions import ValidationError
    from rest_framework_jwt.views import JSONWebTokenSerializer
    
    
    class CostomJSONWebTokenSerializer(JSONWebTokenSerializer):
        # 使用pyjwt
        def verify_username(self, username):
            """多方式登录校验"""
            if re.search(r'^1[3-9][0-9]{9}$', username):
                user = models.User.objects.filter(mobile=username).first()
            elif re.search(r'^.*?@.*?\.com$', username):
                user = models.User.objects.filter(email=username).first()
            else:
                user = models.User.objects.filter(username=username).first()
    
            if user:
                return user
            raise ValidationError("用户名错误!")
    
        def verify_password(self, user, password):
            """校验密码"""
            is_success = user.check_password(raw_password=password)
            if not is_success:
                raise ValidationError("用户密码错误!")
    
        def sign_token(self, user):
            """签发token"""
            headers = {
                'typ': 'jwt',
                'alg': 'HS256',
            }
            payload = {
                'user_id': user.pk,
                'username': user.username,
                'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=300),
            }
    
            slat = settings.SECRET_KEY
            token = jwt.encode(payload=payload, key=slat, headers=headers)
            return token
    
        def validate(self, attrs):
            """校验用户名, 校验密码, 签发token"""
            username = attrs.get('username')
            password = attrs.get('password')
    
            user = self.verify_username(username)
    
            self.verify_password(user, password)
    
            token = self.sign_token(user)
            # 返回什么格式由jwt_response_payload_handler来控制. 因此任然需要重写自定义jwt_response_payload_handler
            return {
                'token': token,
                'user': user
            }
    
    # utils/jwt_response.py 自定义认证成功返回格式:
    from rest_framework_jwt.utils import jwt_response_payload_handler
    
    def custom_jwt_response_payload_handler(token, user=None, request=None):
        # 返回什么, 认证成功时就返回什么格式
        return {
            # 'status': 1000,
            # 'messages': '登录成功',
            'token': token,
            'username': user.username,
        }
    
    
    # 配置文件配置
    JWT_AUTH = {
        'JWT_RESPONSE_PAYLOAD_HANDLER':
        'apps.utils.jwt_response.custom_jwt_response_payload_handler',
    }
    

3. 使用内置的认证+控制登录

  • JSONWebTokenAuthentication要和IsAuthenticated连用, 因为不符合内置的认证返回的是None, 那么就获取不到用户对象, 此时是匿名用户IsAuthenticated就对匿名用户做了认证. 因此2个要搭配使用

    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    # 内置权限类
    # 可以通过认证类JSONWebTokenAuthentication和权限类IsAuthenticated,来控制用户登录以后才能访问某些接口
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    
    # 如果用户不登录就可以访问,只需要把权限类IsAuthenticated去掉即可
    from rest_framework.permissions import IsAuthenticated
    
    class orderAPIView(APIView):
        # 认证控制
        authentication_classes = [JSONWebTokenAuthentication,]
        # 权限控制
        permission_classes = [IsAuthenticated,]
        def get(self,request,*args,**kwargs):
            return Response("这是订单信息,只有登录用户才能访问")
    
    class userInfoAPIView(APIView):
        # 认证控制
        authentication_classes = [JSONWebTokenAuthentication, ]
    
        # 权限控制,区别在这里
        # permission_classes = [IsAuthenticated,]
        def get(self,request,*args,**kwargs):
            return Response("这是用户信息,所有用户都能访问")
    
    

4. 控制返回数据格式

# utils.py自定义认证成功返回数据格式
def my_jwt_response_payload_handler(token, user=None, request=None):
    return {
        'token': token,
        'msg':'登录成功',
        'status':100,
        'username':user.username
    }
# settings.py配置文件
JWT_AUTH = {
  'JWT_RESPONSE_PAYLOAD_HANDLER':'api.utils.my_jwt_response_payload_handler'
}

四、自定义jwt认证+token签发

1. 自定义jwt认证

①、继承BaseAuthentication实现

# 继承BaseAuthentication类,在获取user对象时需要自己手动获取
import jwt
from api import models

from rest_framework_jwt.utils import jwt_decode_handler
# from rest_framework_jwt.authentication import jwt_decode_handler # 和上面的是同一个

from rest_framework.exceptions import AuthenticationFailed
from rest_framework.authentication import BaseAuthentication

class MyBaseAuthentication(BaseAuthentication):
    def authenticate(self, request):
        jwt_value = request.META.get('HTTP_AUTHORIZATION')
        # 如果有jwt_value
        if jwt_value:
            try:
                # jwt提供了通过三段token,取出payload的方法,并且有校验功能
                payload = jwt_decode_handler(jwt_value)
            except jwt.ExpiredSignature:
                raise AuthenticationFailed('签名过期')
            except jwt.InvalidTokenError:
                raise AuthenticationFailed('用户非法')
            except Exception as e:
                # 所有的异常都会走到这里
                raise AuthenticationFailed(str(e))
            # 因为payload就是用户信息的字典
            print(payload)
            # 需要得到user对象
            # 第一种:去数据库中查
            # user = models.User.objects.filter(pk=payload.get('user_id')).first()

            # 第二种:不查库,直接实例一个user对象,此时的user对象功能阉割,字段不全
            user = models.User(id=payload.get('user_id'),username=payload.get('username'))
            return user,jwt_value
        # 没有值,直接抛异常
        raise AuthenticationFailed('请你携带认证信息')

# 全局使用
REST_FRAMEWORK = {
    # 认证模块
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'api.utils.MyBaseAuthentication',
    ),
}

# 局部使用
from api.utils import MyBaseAuthentication
authentication_classes = [MyBaseAuthentication,]

②、继承BaseJSONWebTokenAuthentication 实现

# 继承BaseJSONWebTokenAuthentication,在获取user对象时不需要自己手动获取,直接调用方法即可
import jwt
from api import models

from rest_framework_jwt.utils import jwt_decode_handler
# from rest_framework_jwt.authentication import jwt_decode_handler # 和上面的是同一个
from rest_framework.exceptions import AuthenticationFailed
from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication

class MyBaseJSONWebTokenAuthentication(BaseJSONWebTokenAuthentication):
    def authenticate(self, request):
        jwt_value = request.META.get('HTTP_AUTHORIZATION')
        # 如果有jwt_value
        if jwt_value:
            try:
                # jwt提供了通过三段token,取出payload的方法,并且有校验功能
                payload = jwt_decode_handler(jwt_value)
            except jwt.ExpiredSignature:
                raise AuthenticationFailed('签名过期')
            except jwt.InvalidTokenError:
                raise AuthenticationFailed('用户非法')
            except Exception as e:
                # 所有的异常都会走到这里
                raise AuthenticationFailed(str(e))
            # 因为payload就是用户信息的字典
            print(payload)
            # 需要得到user对象
            user = self.authenticate_credentials(payload)
            return user,jwt_value
        # 没有值,直接抛异常
        raise AuthenticationFailed('请你携带认证信息')
 
# 全局使用
REST_FRAMEWORK = {
    # 认证模块
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'api.utils.MyBaseAuthentication',
    ),
}

# 局部使用
from api.utils import MyBaseJSONWebTokenAuthentication
authentication_classes = [MyBaseJSONWebTokenAuthentication,]

③、继承JSONWebTokenAuthentication实现

# 只需要删除一部分,新增一句代码即可
import jwt
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework_jwt.utils import jwt_decode_handler
from django.utils.translation import ugettext as _
from rest_framework import exceptions


class MyJSONWebTokenAuthentication(JSONWebTokenAuthentication):
    def authenticate(self, request):
        jwt_value = self.get_jwt_value(request)
        # 删除这一部分
        # if jwt_value is None:
        #     return None

        try:
            payload = jwt_decode_handler(jwt_value)
        except jwt.ExpiredSignature:
            msg = _('Signature has expired.')
            raise exceptions.AuthenticationFailed(msg)
        except jwt.DecodeError:
            msg = _('Error decoding signature.')
            raise exceptions.AuthenticationFailed(msg)
        except jwt.InvalidTokenError:
            raise exceptions.AuthenticationFailed()

        # 新增这一部分
        except Exception as e:
            raise exceptions.AuthenticationFailed(str(e))

        user = self.authenticate_credentials(payload)

        return (user, jwt_value)
    
# 全局使用
REST_FRAMEWORK = {
    # 认证模块
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'api.utils.MyJSONWebTokenAuthentication',
    ),
}

# 局部使用
from api.utils import MyJSONWebTokenAuthentication
authentication_classes = [MyJSONWebTokenAuthentication,]

2. 自定义token签发

①、多方式登录,逻辑写在视图中

# 视图代码
from rest_framework.exceptions import ValidationError
from rest_framework import serializers
from rest_framework_jwt.utils import jwt_encode_handler,jwt_payload_handler
from api import models
import re


class LoginAPIView(ViewSet):
    """
    继承ViewSet意义:
    	1. ViewSet = APIView + ViewSetMixin
        2. 修改视图类中方法, 使用login明确提意
        3. 继承了APIView, 具有较高的可控性
    """
    def login(self, request, *args, **kwargs):
        username = request.data.get('username')
        password = request.data.get('password')

        # username=egon/111@qq.com/17621839222
        if re.match("^1[3-9][0-9]{9}$",username): # 手机号登录
            user = models.User.objects.filter(mobile=username).first()
        elif re.match("^.+@.+$",username): # 邮箱登录(只要带有@就认为是邮箱)
            user = models.User.objects.filter(email=username).first()
        else: # 用户名登录
            user = models.User.objects.filter(username=username).first()

         # 判断密码是否正确
        if user: # 判断用户是否存在
            # 此处必须使用check_password,因为密码是密文处理的
            if user.check_password(password):
                # 此处需要手动签发token串
                payload = jwt_payload_handler(user)  # 传入user对象,生成payload串
                token = jwt_encode_handler(payload)  # 传入payload串,生成token串
                return Response({'status': 1000, 'token': token, 'results': {'username': user.username, 'email': user.email}})
            raise ('用户密码错误!')
        raise ValidationError("用户名错误!")

②、多方式登录,逻辑写在序列化类中

# 视图代码
from rest_framework.views import APIView
from rest_framework.viewsets import ViewSetMixin,ViewSet
from api import ser

class LoginView(ViewSet): 
    def login(self,request,*args,**kwargs):
        # 1.需要有一个序列化类,生成序列化类对象
        login_ser = ser.LoginModelSerializer(data=request.data,context={})

        # 2.调用序列化对象的is_valid方法
        login_ser.is_valid(raise_exception=True)
        token = login_ser.context.get('token')
        username = login_ser.context.get('username')

        # 3.return返回数据
        return Response(data={'status':100,'msg':'成功','token':token,'username':username})


# 序列化器代码
from rest_framework.exceptions import ValidationError
from rest_framework import serializers
from rest_framework_jwt.utils import jwt_encode_handler,jwt_payload_handler
from api import models
import re

class LoginModelSerializer(serializers.ModelSerializer):
    # 此处必须覆盖username,因为fields中的username是直接对应表中的username,
    # 它是唯一的,如果不覆盖,就会抛出该用户已存在的异常,而不会走到validate方法
    username = serializers.CharField()

    class Meta:
        model = models.User
        fields = ['username','password']

    # 只要视图类中调用了is_valid方法,就会走validate方法
    def validate(self, attrs):
        # 在这里写多种登录方式的逻辑
        username = attrs.get('username')
        password = attrs.get('password')
        if re.match("^1[3-9][0-9]{9}$",username): # 手机号登录
            user = models.User.objects.filter(mobile=username).first()
        elif re.match("^.+@.+$",username): # 邮箱登录(只要带有@就认为是邮箱)
            user = models.User.objects.filter(email=username).first()
        else: # 用户名登录
            user = models.User.objects.filter(username=username).first()

        # 判断密码是否正确
        if user: # 判断用户是否存在
            # 此处必须使用check_password,因为密码是密文处理的
            if user.check_password(password):
                # 此处需要手动签发token串
                payload = jwt_payload_handler(user)  # 传入user对象,生成payload串
                token = jwt_encode_handler(payload)  # 传入payload串,生成token串
                self.context['token'] = token
                self.context['username'] = user.username
                return attrs
            else: # 密码不正确,抛出密码错误异常
                raise ValidationError("密码错误")
        else: # 用后不存在,抛出用户不存在异常
            raise ValidationError('当前用户不存在')


"""
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

payload = jwt_payload_handler(user) # 传入user对象,生成payload串
token = jwt_encode_handler(payload) # 传入payload串,生成token串
"""

③、多方式登录,逻辑写在序列化类中+解耦合

# 路由代码:
url(r'^login/', views.LoginView.as_view(actions={'post': 'login'})),

# 视图代码
from rest_framework.views import APIView
from rest_framework.viewsets import ViewSetMixin,ViewSet
from api import ser

class LoginView(ViewSet): 
    def login(self,request,*args,**kwargs):
        # 1.需要有一个序列化类,生成序列化类对象
        login_ser = ser.LoginModelSerializer(data=request.data,context={})

        # 2.调用序列化对象的is_valid方法
        login_ser.is_valid(raise_exception=True)
        token = login_ser.context.get('token')
        username = login_ser.context.get('username')

        # 3.return返回数据
        return Response(data={'status':100,'msg':'成功','token':token,'username':username})
    
    
# 序列化器代码
import re
from rest_framework import serializers
from rest_framework_jwt.utils import jwt_payload_handler
from rest_framework_jwt.utils import jwt_encode_handler

from rest_framework.exceptions import ValidationError

from . import models


class LoginModelSerializer(serializers.ModelSerializer):
    """登陆接口,jwt方式返回token,格式为{status:100,msg:登陆成功,token:safasdfa}"""

    # 此处必须覆盖username,因为fields中的username是直接对应表中的username,
    # 它是唯一的,如果不覆盖,就会抛出该用户已存在的异常,而不会走到validate方法
    username = serializers.CharField()

    class Meta:
        model = models.User
        fields = ['username','password']

    # 使用drf-jwt实现没有解耦合之前
    # def validate(self, validate_data):
    #     print('validate_data:', validate_data)
    #     username = validate_data.get('username')
    #     password = validate_data.get('password')
    #     # 支持多方式登录
    #     if re.search(r'^1[3-9][0-9]{9}$', username):
    #         user = models.User.objects.filter(mobile=username).first()
    #     elif re.search(r'^.*?@.*?\.com$', username):
    #         user = models.User.objects.filter(email=username).first()
    #     else:
    #         user = models.User.objects.filter(username=username).first()
    #
    #     if not user.is_delete:
    #         if user:
    #             if user.check_password(raw_password=password):
    #                 # 签发token
    #                 payload = jwt_payload_handler(user)
    #                 token = jwt_encode_handler(payload)
    #                 self.context['token'] = token
    #                 self.context['user'] = user
    #                 return validate_data
    #             else:
    #                 raise ValidationError('用户密码错误!')
    #         raise ValidationError('用户名错误!')
    #     raise ValidationError('该用户已经被管理员注销!')

    def verify_username(self, username):
        """校验用户不同登录方式"""
        if re.match("^1[3-9][0-9]{9}$",username): # 手机号登录
            user = models.User.objects.filter(mobile=username).first()
        elif re.match("^.+@.+$",username): # 邮箱登录(只要带有@就认为是邮箱)
            user = models.User.objects.filter(email=username).first()
        else: # 用户名登录
            user = models.User.objects.filter(username=username).first()

        if user:
            return user
        raise ValidationError('用户名错误!')

    def verify_password(self, user, password):
        """校验密码"""
        is_succeed = user.check_password(raw_password=password)
        if not is_succeed:
            raise ValidationError('用户密码错误!')

    def sign_token(self, user):
        """签发token"""
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        self.context['token'] = token
        self.context['user'] = user

    def validate(self, validate_data):
        """校验用户,密码,签发token接口"""
        print('validate_data:', validate_data)
        username = validate_data.get('username')
        password = validate_data.get('password')
        # 校验用户
        user = self.verify_username(username)
        # 校验密码
        self.verify_password(user, password)

        # 签发token
        self.sign_token(user)
        return validate_data

五、jwt参数配置

# settings.py配置信息
JWT_AUTH = {
    # token编码方法
    'JWT_ENCODE_HANDLER':
    'rest_framework_jwt.utils.jwt_encode_handler',
	
    # token解码方法
    'JWT_DECODE_HANDLER':
    'rest_framework_jwt.utils.jwt_decode_handler',

    # 获取payload串方法
    'JWT_PAYLOAD_HANDLER':
    'rest_framework_jwt.utils.jwt_payload_handler',

    # 通过payload可以获取user_id
    'JWT_PAYLOAD_GET_USER_ID_HANDLER':
    'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler',

    # 签名加密,默认是None,就去settings.py中找SECRET_KEY = 'jep)^#5c_@us3#oc@m1c*11dw@zkqn80ku(_d^_%+u382=kz6_'
    'JWT_PRIVATE_KEY':
    None,

    'JWT_PUBLIC_KEY':
    None,

    'JWT_PAYLOAD_GET_USERNAME_HANDLER':
    'rest_framework_jwt.utils.jwt_get_username_from_payload_handler',

    'JWT_RESPONSE_PAYLOAD_HANDLER':
    'rest_framework_jwt.utils.jwt_response_payload_handler',

    'JWT_SECRET_KEY': settings.SECRET_KEY,
    'JWT_GET_USER_SECRET_KEY': None,
    
    # 加密方式
    'JWT_ALGORITHM': 'HS256',
    'JWT_VERIFY': True,
    'JWT_VERIFY_EXPIRATION': True,
    'JWT_LEEWAY': 0,
    # 过期时间,5分钟过期
    'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300),
    
    'JWT_AUDIENCE': None,
    'JWT_ISSUER': None,

    'JWT_ALLOW_REFRESH': False,
    
    # 默认是7天免登陆
    'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),

    # 头部访问格式
    'JWT_AUTH_HEADER_PREFIX': 'JWT',
    'JWT_AUTH_COOKIE': None,
}

六、base64的使用

"""
base64:可变长,可反解
md5:不可变长,不可反解
"""

import base64
import json

# 使用base64进行解密
base64_str = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9'
bytes_json = base64.b64decode(base64_str.encode('utf-8'))
header = json.loads(bytes_json)   # {'typ': 'JWT', 'alg': 'HS256'}
print(header)


# 使用base64进行加密
json_str = json.dumps(header)
base64_bytes = base64.b64encode(json_str.encode('utf-8'))
base64_str = base64_bytes.decode('utf-8')
print(base64_str)   # eyJ0eXAiOiAiSldUIiwgImFsZyI6ICJIUzI1NiJ9

推荐阅读