当前位置 博文首页 > DRF使用simple JWT身份验证的实现

    DRF使用simple JWT身份验证的实现

    作者:一切如来心秘密 时间:2021-02-10 18:03

    前言

    在Django的前后端分离项目中DRF(Django Restframe Work)框架无疑是首选,关于token验证一般使用的是JWT,但是JWT只支持到Django1.x的版本。

    官方推荐Django2.x之后的版本使用simple JWT,官方文档。

    登录返回token和refresh

    user 模型类:

    我user模型类继承的是django.contrib.auth.models.AbstractUser,这样可以使用Django自带的认证。

    如果继承该类,我们就必须在settings中配置 AUTH_USER_MODEL = "users.UserProfile"

    from datetime import datetime
    
    from django.db import models
    from django.contrib.auth.models import AbstractUser
    # Create your models here.
    
    class UserProfile(AbstractUser):
      """
      用户
      """
      name = models.CharField(max_length=30, null=True, blank=True, verbose_name="姓名")
      birthday = models.DateField(null=True, blank=True, verbose_name="出生年月")
      gender = models.CharField(max_length=6, choices=(("male", u"男"), ("female", "女")), default="female", verbose_name="性别")
      mobile = models.CharField(null=True, blank=True, max_length=11, verbose_name="电话")
      email = models.CharField(max_length=100, null=True, blank=True, verbose_name="邮箱")
    
      class Meta:
        verbose_name = "用户"
        verbose_name_plural = "用户"
    
      def __str__(self):
        return self.username

    序列化文件:

    注意这里使用的User是Django管理的user模型类,要从django.contrib.auth.get_user_model实例化获取。

    users模块的serializers.py文件中写如下序列化类继承自rest_framework_simplejwt.serializers.TokenObtainPairSerializer

    在这里插入图片描述

    from django.contrib.auth import get_user_model
    User = get_user_model()
    
    class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
      @classmethod
      def get_token(cls, user):
        token = super().get_token(user)
        token['name'] = user.username
        return token
    
      def validate(self, attrs):
        """
        登录返回token和refresh
        :param attrs:
        :return:
        """
        data = super().validate(attrs)
        data['token'] = str(data["access"])
        return data

    根据官方文档的说明,get_token方法之所以设置token['name']是因为程序可能运行在集群上,这里不写也可以。

    编写视图类

    from users.serializers import MyTokenObtainPairSerializer
    
    class MyTokenObtainPairView(TokenObtainPairView):
      serializer_class = MyTokenObtainPairSerializer

    编写url:

    其中api/token/api/token/refresh/两个URL是simple JWT自带的token方法:

    • api/token/用于获取token
    • api/token/refresh/用于刷新token
    from django.conf.urls import url
    from django.urls import include, path
    
    from rest_framework_simplejwt.views import (
      TokenObtainPairView,
      TokenRefreshView,
    )
    
    urlpatterns = [
      # simple jwt 认证接口
      path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
      path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
      path('login/', MyTokenObtainPairView.as_view(), name='token_obtain_pair'),
    ]

    settings配置SIMPLE_JWT:

    这是对token的一些自定义设置包括获取的token和refresh的生命周期等配置,通过查看rest_framework_simplejwt的源码可以发现有很多自定义配置,感兴趣的小伙伴可以通过查看官方文档了解更多,这里我只配置了获取的token的生命周期。

    启动程序访问:

    在这里插入图片描述

    在这里插入图片描述

    可以发现返回了三个值:

    • refresh:是刷新token用的,当前端token过期需要刷新token的时候就可以访问前边说的api/token/refreshurl,参数就是refresh的值。
    • access:这个就是token但是框架里叫做access。
    • token:这个是在序列化文件中给access新命名了一个值,方便前端获取:
    def validate(self, attrs):
      """
      登录返回token和refresh
      :param attrs:
      :return:
      """
      data = super().validate(attrs)
      data['token'] = str(data["access"])
      return data

    注册返回token

    视图类:

    • 在视图类中导入from rest_framework_simplejwt.tokens import RefreshToken
    • 重写create方法,需要通过前边导入的RefreshToken来获取token返回给前端。
    from django.contrib.auth import get_user_model
    from django.db.models import Q
    from rest_framework.response import Response
    from rest_framework_simplejwt.tokens import RefreshToken
    from rest_framework.mixins import CreateModelMixin
    from rest_framework import viewsets
    from rest_framework import status
    
    from users.serializers import (
      UserRegSerializer
    )
    from .models import VerifyCode
    
    User = get_user_model()
    
    
    class UserViewSet(CreateModelMixin, viewsets.GenericViewSet):
      """
      用户
      """
      serializer_class = UserRegSerializer
      queryset = User.objects.all()
    
      def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = self.perform_create(serializer)
    
        ret_dict = serializer.data
        refresh = RefreshToken.for_user(user)
        access_token = str(refresh.access_token)
        ret_dict["token"] = access_token
    
        headers = self.get_success_headers(serializer.data)
        return Response(ret_dict, status=status.HTTP_201_CREATED, headers=headers)
    
      def perform_create(self, serializer):
        return serializer.save()
    js