django--user

乌修筠
2023-12-01
from django.shortcuts import render
from rest_framework.views import APIView
from django.http import HttpResponse
from meiduo_mall.libs.captcha.captcha import captcha
from django_redis import get_redis_connection
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
import random
import logging

from . import constants
from meiduo_mall.libs.yuntongxun.sms import CCP
from . import serializers
from celery_tasks.sms.tasks import send_sms_code
# Create your views here.


# 日志记录器
logger = logging.getLogger('django')


# url('^sms_codes/(?P<mobile>1[3-9]\d{9})/$', views.SMSCodeView.as_view()),
class SMSCodeView(GenericAPIView):
    """发送短信验证码"""

    # 指定序列化器
    serializer_class = serializers.ImageCodeCheckSerializer

    def get(self, request, mobile):
        # 创建序列化器对象:data=request.query_params 是将url中的查询字符串传入到序列化器中
        serializer = self.get_serializer(data=request.query_params)
        # 开启校验
        serializer.is_valid(raise_exception=True)

        # 生成短信验证码 0
        sms_code = '%06d' % random.randint(0, 999999)
        logger.info(sms_code)

        # 存储短信验证码到redis数据库
        redis_conn = get_redis_connection('verify_codes')
        # redis_conn.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
        #
        # # 记录用户发送短信的频次
        # redis_conn.setex('send_flag_%s' % mobile, constants.SEND_SMS_CODE_INTERVAL, 1)

        # 创建管道
        pl = redis_conn.pipeline()
        pl.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
        # 记录用户发送短信的频次
        pl.setex('send_flag_%s' % mobile, constants.SEND_SMS_CODE_INTERVAL, 1)
        # 开启执行
        pl.execute()

        # 发送短信验证码
        # CCP().send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES // 60], constants.SEND_SMS_TEMPLATE_ID)

        # 调用异步任务,将异步任务发送不到broker任务队列中
        # 使用delay函数
        send_sms_code.delay(mobile, sms_code)

        # 响应结果
        return Response({'message':'OK'})


# url('^image_codes/(?P<image_code_id>[\w-]+)/$', views.ImageCodeView.as_view()),
class ImageCodeView(APIView):
    """提供图片验证码"""

    def get(self, request, image_code_id):
        # 生成图片验证码:text是验证码内容,需要保存到Redis;image是图片验证码数据,需要响应给前端
        text, image = captcha.generate_captcha()

        # 将图片验证码内容存储到redis数据库
        redis_conn = get_redis_connection('verify_codes')
        # redis_conn.setex('key', 'expires', 'value')
        redis_conn.setex('img_%s'%image_code_id, constants.IMAGE_CODE_REDIS_EXPIRES, text)

        # 将图片验证码图片数据响应到前端
        return HttpResponse(image, content_type='image/jpg')
#serializers----------------------------------------------------------------------------
from rest_framework import serializers
from django_redis import get_redis_connection
from redis import RedisError
import logging


# 日志记录器
logger = logging.getLogger('django')


class ImageCodeCheckSerializer(serializers.Serializer):
    """图片验证码序列化器"""

    # 定义待校验的字典:定义的字段名字,必须和外界传入的一致
    image_code_id = serializers.UUIDField()
    text = serializers.CharField(max_length=4, min_length=4)

    def validate(self, attrs):
        """对比服务图片验证码和客户端传入图片验证码"""

        # 取出经过字段校验后的数据
        image_code_id = attrs['image_code_id']
        text = attrs['text']

        # 使用image_code_id查询出redis中存储的图片验证码
        redis_conn = get_redis_connection('verify_codes')
        image_code_server = redis_conn.get('img_%s' % image_code_id)
        if image_code_server is None:
            raise serializers.ValidationError('无效图片验证码')

        # 在获取到image_code_server之后,对比text之前
        # 删除Redis图片验证码:防止暴力测试
        try:
            redis_conn.delete('img_%s' % image_code_id)
        except RedisError as e:
            logger.error(e)

        # 对比客户端和服务器的验证阿妈
        # 因为py3中的redis,存储的数据都是bytes类型的,而在读取时也是保持原始的bytes类型,因为快
        image_code_server = image_code_server.decode()
        if text.lower() != image_code_server.lower():
            raise serializers.ValidationError('输入图片验证码有误')

        # 删除Redis图片验证码:如果比较一致失败,无法删除

        # 校验60s内是否重复发送短信验证码
        mobile = self.context['view'].kwargs['mobile']
        send_flag = redis_conn.get('send_flag_%s' % mobile)
        if send_flag:
            raise serializers.ValidationError('发送短信验证码过于频繁')

        return attrs

 

 类似资料: