验证码的开发(自定义)

一、准备工作(在django中配置redis的缓存)

  • 1、电脑上安装redis

    brew install redis
    
  • 2、启动redis(启动成功会出现图标)

    redis-server
    
  • 3、测试安装是否成功(命令窗口中输入)

    redis-cli
    
  • 4、给reids设置密码

    CONFIG SET requirepass "123456"
    
  • 5、安装包

    pipenv install django-redis
    
  • 6、在settings.py中配置缓存

    # 配置redis缓存
    CACHES = {
        "default": {
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": "redis://:[email protected]:6379",  # 这里设定了本机的redis数据
            # "LOCATION": "redis://127.0.0.1:6379", # 如果redis没设置密码就这样
            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.DefaultClient",
            }
        }
    }
    

二、生成随机字符的函数

  • 1、定义一个生成随机字符的函数

    import random
    import string
    
    def random_str(num=4):
        """
        定义一个生产随机字符的函数
        :param num: 返回字符多少
        :return:
        """
        # string.ascii_letters是生成全部的字符(a-zA-Z)
        source = list(string.ascii_letters)
        for index in range(0, 10):
            source.append(str(index))
        return ''.join(random.sample(source, num))
    

三、单独封装一个工具类用来生成图片验证码

  • 1、安装图片的包

    pip install Pillow
    
  • 2、定义生成验证码的类

    import random
    # 引入绘图的包
    from PIL import Image, ImageDraw, ImageFont, ImageFile
    # 引入缓存的包
    from django.core.cache import cache
    # 引入自定义的生成随机字符的函数
    from .random_str import random_str
    
    class Captcha(object):
        """
        定义验证码的类
        """
        # 选用的字体的路径
        font_path = 'Arial.ttf'
        # 生成几位数的验证码
        number = 4
        # 生成验证码图片的宽度与高度
        size = (100, 30)
        # 背景颜色,默认是白色
        bgcolor = (255, 255, 255)
        # 字体颜色,默认为蓝色
        fontcolor = (random.randint(0, 100), random.randint(0, 100), random.randint(0, 100))
        # 验证码字体大小
        fontsize = 25
        # 干扰线的颜色,默认是红色
        linecolor = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
        # 是否要加入干扰线
        draw_line = True
        # 是否绘制干扰点
        draw_point = True
        # 加入干扰线的条数
        line_number = 2
    
        # 定义一个类方法绘制干扰线
        @classmethod
        def __gene_line(cls, draw, width, height):
            # 开始位置
            begin = (random.randint(0, width), random.randint(0, height))
            # 结束位置
            end = (random.randint(0, width), random.randint(0, height))
            draw.line([begin, end], fill=cls.linecolor)
    
        # 定义一个类方法绘制干扰点
        @classmethod
        def __gene_points(cls, draw, point_chance, width, height):
            chance = min(100, max(0, int(point_chance)))  # 大小限制在[0, 100]
            for w in range(width):
                for h in range(height):
                    tmp = random.randint(0, 100)
                    if tmp > 100 - chance:
                        draw.point((w, h), fill=(0, 0, 0))
    
        # 生成验证码
        @classmethod
        def gene_code(cls):
            width, height = cls.size  # 宽和高
            image = Image.new('RGBA', (width, height), cls.bgcolor)  # 创建图片
            font = ImageFont.truetype(cls.font_path, cls.fontsize)  # 验证码的字体
            draw = ImageDraw.Draw(image)  # 创建画笔
            text = random_str(4)  # 生成字符串
            font_width, font_height = font.getsize(text)
            draw.text(((width - font_width) / 2, (height - font_height) / 2), text, font=font,
                      fill=cls.fontcolor)  # 填充字符串
            # 如果需要绘制干扰线
            if cls.draw_line:
                # 遍历line_number次,就是画line_number根线条
                for x in range(0, cls.line_number):
                    cls.__gene_line(draw, width, height)
            # 如果需要绘制噪点
            if cls.draw_point:
                cls.__gene_points(draw, 10, width, height)
            # 保存到缓存中,过期时间为2分钟
            cache.set(text.lower(), text.lower(), 120)
            return (text, image)
    
        # 验证验证码
        @classmethod
        def check_captcha(cls, captcha):
            captcha_cache = cache.get(captcha)
            if captcha_cache and captcha_cache == captcha:
                # 删除缓存
                cache.delete(captcha)
                return True
            else:
                return False
    

四、视图的书写

  • 1、导包

      from io import BytesIO
      from django.shortcuts import HttpResponse
      from django.views.generic import View
    
      # 引入生成验证码的类
      from utils.captcha import Captcha
    
  • 2、视图类使用BytesIO返回图片

      class CaptchaView(View):
              """
              定义一个图片验证码的视图
              """
    
              def get(self, request, *args, **kwargs):
                      text, image = Captcha.gene_code()
                      out = BytesIO()
                      image.save(out, 'png')
                      out.seek(0)
                      # 设置返回请求头
                      response = HttpResponse(content_type='image/png')
                      response.write(out.read())
                      return response
    

五、配置url及浏览访问

  • 1、url的配置

      from django.urls import path
      from .views import login, register, captcha
    
      urlpatterns = [
              ...
              path('captcha/', captcha.CaptchaView.as_view(), name='captcha')
      ]
    
  • 2、浏览器中访问

六、校验验证码的合法性

  • 1、还是使用用户注册的时候添加一个验证码

  • 2、在forms.py中校验用户输入的验证码合法性

      from utils.captcha import Captcha
      class RegisterForm(forms.Form):
              """
              用户注册的form
              """
              email = forms.EmailField(required=True, error_messages={'required': '用户名不能为空'})
              password = forms.CharField(required=True, min_length=5,
                                                                  error_messages={'required': '密码不能为空', 'min_length': '密码长度太短'})
              captcha = forms.CharField(max_length=4, min_length=4)
    
              def clean_captcha(self):
                      # 获取用户输入的验证码
                      captcha = self.cleaned_data.get('captcha', None)
                      if Captcha.check_captcha(captcha=captcha):
                              return captcha
                      else:
                              raise forms.ValidationError('验证码错误')
    
  • 3、前端用户点击验证码切换

      $('#captcha').on('click', function () {
              var base_url = $(this).attr('src').split('?')[0];
              var new_url = `${base_url}?${+new Date()}`;
              $(this).attr('src', new_url);
      })
    

七、关于缓存的认识更多可以参考

results matching ""

    No results matching ""