django基于rest_framework_simplejwt实现token认证

5,336 阅读2分钟

Django drf基于rest_framework_simplejwt实现登陆获取token、校验token、刷新token有效期

安装rest_framework_simplejtw
配置settings.py
配置路由
测试rest_framework_simplejwt自带token相关接口
使用token
djangorestframework-simplejwt定制
测试djangorestframework-simplejwt定制

安装rest_framework_simplejwt

pip install djangorestframework-simplejwt 安装djangorestframework-simplejwt.png

配置settings.py

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        # 默认所有接口都需要token认证
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        # simplejwt 认证
        'rest_framework_simplejwt.authentication.JWTAuthentication',
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    )
INSTALLED_APPS = [
    'rest_framework',
    # 引入token认证
    'rest_framework.authtoken',
]
JWT_AUTH = {
    # token有效期
    'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300),
    # token刷新后的有效时间 
    'REFRESH_TOKEN_LIFETIME': datetime.timedelta(minutes=30),
}
}

配置路由

# rest_framework_simplejwt 提供的现成视图类
from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
    TokenVerifyView,
)
urlpatterns = [
    path('admin/', admin.site.urls),
    # JTW认证接口
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    # 刷新JWT有效期接口
    path('api/refresh', TokenObtainPairView.as_view(), name='token_refresh'),
    # 验证token有效期接口
    path('api/token/verify/', TokenVerifyView.as_view(), name='token_verify')
]

测试rest_framework_simplejwt自带token相关接口

获取token接口

获取token接口.png

刷新token有效期接口

刷新token有效期.png

验证token有效期接口

验证token有效期.png

使用token

测试失效的token

测试失效token.png 测试生效的token

截屏2022-08-01 上午5.11.23 (2).png

djangorestframework-simplejwt定制

目标:实现登陆接口 先写序列化器
from django.contrib.auth import get_user_model
from rest_framework.serializers import ModelSerializer
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer

# 重写了User模型,所以通过get_user_model获取User模型对象
User = get_user_model()


# 重写TokenObtainPairSerializer类的部分方法以实现自定义数据响应结构和payload
class MyTokenSerializer(TokenObtainPairSerializer):

  @classmethod
  def get_token(cls, user):
    """
    往token有效负载payload里添加数据
    """
    token = super().get_token(user)
    token['name'] = user.username
    return token

  def validate(self, attrs):
    """
    响应数据结构处理重写为以下结构
    {
      "refresh": "...",
      "access": "...",
      "expire": 有效期时间戳,
      "username": "...",
      "email": "..."
    }
    """
    # data是个字典
    # 其结构为:{'refresh': '用于刷新token的令牌', 'access': '用于身份验证的Token值'}
    data = super().validate(attrs)
    # 获取token对象
    refresh = self.get_token(self.user)
    # 修改原data对象的键access为token
    data['token'] = data['access']
    # 删除data对象的access键
    del data['access']
    # 增加有效期信息
    data['expire'] = refresh.access_token.payload['exp']
    # 增加用户名信息
    data['username'] = self.user.username
    # 增加email信息
    data['email'] = self.user.email
    return data

再写视图类

from .serializers import MyTokenSerializer
from rest_framework import status
from rest_framework.response import Response
from rest_framework_simplejwt.views import TokenViewBase


# Create your views here.
class LoginView(TokenViewBase):
  serializer_class = MyTokenSerializer
  # 暂时只写了正确用户名和密码的处理逻辑
  def post(self, request, *args, **kwargs):
    serializer = self.get_serializer(data=request.data)
    try:
      serializer.is_valid(raise_exception=True)
    except Exception as e:
      raise ValueError(f'验证失败:{e}')
    return Response(serializer.validated_data, status=status.HTTP_200_OK)

注册一级路由

urlpatterns = [
    path('admin/', admin.site.urls),
    # 用户登陆接口
    path('api/users/', include('users.urls')),
    # JTW认证接口
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    # 刷新JWT有效期
    path('api/token/refresh/', TokenObtainPairView.as_view(), name='token_refresh'),
    # 验证token有效期接口
    path('api/token/verify/', TokenVerifyView.as_view(), name='token_verify'),
    path('api/book/', BookView.as_view(), name='book')
]

注册二级路由

from django.urls import path
from .views import LoginView

urlpatterns = [
  path('login/', LoginView.as_view(), name="login")
]

测试djangorestframework-simplejwt定制

截屏2022-08-01 下午11.40.03 (2).png