DjangoRestFramework實現JWT登錄,並將token緩存到redis中


  1. 創建一個Django應用FirstApp,並實現用戶注冊接口,用戶注冊功能實現見上篇用戶注冊,調用接口創建一個用戶數據(包含用戶名密碼),項目結構如下
    screenshot_2.png

  2. 安裝DjangoJWT

    • pip3 install djangorestframework-jwt
      screenshot_9.png
  3. 項目目錄下settings.py文件中配置DjangoJWT

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny',
    ]
}

JWT_AUTH = {
    # token有效期為24小時
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
}
  1. 安裝Django redis

    • pip3 install django-redis
      screenshot.png
  2. 項目目錄下settings.py文件中配置redis緩存

CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://@127.0.0.1:6379/1",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }
}
  1. 應用中設計urls.py
# -*-coding:utf-8-*-
from rest_framework.routers import DefaultRouter
from FirstApp import views


router = DefaultRouter()
router.register(r'api/auth/tokens', views.TokenViewSet)
  1. 應用中設計User模型類,這里重點寫的是設置密碼和校驗密碼的方法,后面JWT登錄校驗密碼時會用到check_password方法
import uuid

from django.contrib.auth.models import AbstractUser
from django.db import models

from utils.encrypt_password import encrypt_password


class UUIDTools(object):
    @staticmethod
    def uuid4_hex():
        return uuid.uuid4().hex


class User(models.Model):
    # default指定的是一個類,每次會創建一個新的對象,然后調用相關方法
    id = models.UUIDField(primary_key=True, auto_created=True, default=UUIDTools.uuid4_hex, editable=False)
    username = models.CharField(max_length=32, unique=True)

    password = models.CharField(max_length=256)
    # null=True, blank=True, 表示創建用戶時該字段為可選字段
    mobile = models.CharField(max_length=11, blank=True, unique=True)
    email = models.EmailField(max_length=64, blank=True, unique=True)

    def set_password(self, password):
        self.password = encrypt_password(password)

    def check_password(self, password):
        return self.password == encrypt_password(password)
  1. 設計序列化器類UserSerializer
# -*-coding:utf-8-*-
from rest_framework import serializers

from FirstApp.models import User


class UserSerializer(serializers.ModelSerializer):
    # style表示前台輸入是密文,write_only表示序列化時不會序列化該字段
    password = serializers.CharField(style={'input_type': 'password'}, write_only=True, max_length=256)

    class Meta:
        model = User
        fields = ('id', 'username', 'password', 'mobile', 'email')

    # 創建用戶時更新密碼為密文
    def create(self, validated_data):
        user = super().create(validated_data)
        user.set_password(validated_data['password'])
        user.save()
        return user

    # 更新用戶時更新密碼為密文
    def update(self, instance, validated_data):
        user = super().update(instance, validated_data)
        if 'password' in validated_data.keys():
            user.set_password(validated_data['password'])
        user.save()
        return user

    # 重寫to_representation方法,自定義響應中的json數據
    def to_representation(self, instance):
        # 返回結果中id字段中間有橫線,需要去除
        ret = super().to_representation(instance)
        ret['id'] = ret['id'].replace('-', '')
        return ret
  1. 應用中views.py設計視圖類TokenViewSet
# -*-coding:utf-8-*-
from django.core.cache import cache
from rest_framework import status, exceptions
from rest_framework.mixins import CreateModelMixin
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet, GenericViewSet
from rest_framework_jwt.settings import api_settings
from FirstApp.models import User
from FirstApp.serializers import UserSerializer


class TokenViewSet(CreateModelMixin, GenericViewSet):
    queryset = User.objects.all()

    def create(self, request, *args, **kwargs):
        username = request.data.get('username')
        password = request.data.get('password')

        # 校驗用戶名和密碼
        users = User.objects.filter(username=username)
        if not users.exists():
            raise exceptions.NotFound(detail='用戶不存在')

        user = users.first()

        if not user.check_password(password):
            raise exceptions.ValidationError(detail='密碼錯誤')

        # 手動簽發token
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)

        # 將token存到redis緩存中
        cache.set(token, user, 60 * 60 * 24)
        user_id = str(user.id).replace('-', '')
        # 響應數據
        data = {
            'token': token,
            'user_id': user_id,
            'user_name': user.username
        }
        headers = self.get_success_headers(data)

        return Response(data, status=status.HTTP_201_CREATED, headers=headers)
  1. postman通過用戶名密碼獲取token,效果圖如下

screenshot_1.png


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM