• 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

  • 相关阅读:
    Bootstrap3 代码-代码块
    DB2 911错误的解释
    Bootstrap3 代码-用户输入
    Bootstrap3 代码-内联代码
    Bootstrap3 排版-列表
    Bootstrap3 排版-引用
    Bootstrap3 排版-地址
    Bootstrap3 排版-缩略语
    Bootstrap3 排版-改变大小写
    Bootstrap3 排版-对齐
  • 原文地址:https://www.cnblogs.com/iread9527/p/12685770.html
Copyright © 2020-2023  润新知