Django 验证码功能

1、在 Django 项目下新建文件夹 utils,在此目录下新建 code.py 文件,文件内容如下
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter


def check_code(width=100, height=34, char_length=4, font_file='kumo.ttf', font_size=28):
    code = []
    img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))
    draw = ImageDraw.Draw(img, mode='RGB')

    def rndChar():
        """
        生成随机字母
        :return:
        """
        r = random.randint(0, 10)
        if r < 5: #小于5生成数字,大于5生成字母
            return chr(random.randint(48, 57))  # 生成 0 - 9 数字
        return chr(random.randint(65, 90))  # 生成 A-Z 字母

    def rndColor():
        """
        生成随机颜色
        :return:
        """
        return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))

    # 写文字
    font = ImageFont.truetype(font_file, font_size)
    for i in range(char_length):
        char = rndChar()
        code.append(char)
        h = random.randint(0, 4)
        draw.text([i * width / char_length, h], char, font=font, fill=rndColor())

    # 写干扰点
    for i in range(10):
        draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())

    # 写干扰圆圈
    for i in range(10):
        draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
        x = random.randint(0, width)
        y = random.randint(0, height)
        draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())

    # 画干扰线
    for i in range(2):
        x1 = random.randint(0, width)
        y1 = random.randint(0, height)
        x2 = random.randint(0, width)
        y2 = random.randint(0, height)

        draw.line((x1, y1, x2, y2), fill=rndColor())

    img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
    return img, ''.join(code)

    # 1. 直接打开
    # img,code = check_code()
    # img.show()

    # 2. 写入文件
    # img, code = check_code()
    # with open('code.png', 'wb') as f:
    #     img.save(f, format='png')

    # 3. 写入内存(Python3)
    # from io import BytesIO
    # stream = BytesIO()
    # img.save(stream, 'png')
    # stream.getvalue()

    # 4. 写入内存(Python2)
    # import StringIO
    # stream = StringIO.StringIO()
    # img.save(stream, 'png')
    # stream.getvalue()

2、在视图接口目录里写接口函数,如:views 文件夹 下的 login.py 中,内容如下

from django.shortcuts import render, HttpResponse, redirect
from django import forms
from web import models
from django.views.decorators.csrf import csrf_exempt
import json
from web.utils.code import check_code  # 导入生成验证码

# class LoginForm(forms.Form):
#     username = forms.CharField(label="用户名", widget=forms.TextInput,required=True)
#     password = forms.CharField(label="密码", widget=forms.PasswordInput,required=True)

from io import BytesIO


# 验证码
@csrf_exempt
def image_code(request):
    """ 生成图片验证码 """
    img, code_string = check_code()
    print(code_string)

    # 将验证码内容写入到自己的 session 中(以便于后续获取验证码再进行校验)
    request.session['image_code'] = code_string
    # 给 session 设置60秒超时
    request.session.set_expiry(60)

    stream = BytesIO()
    img.save(stream, 'png')
    return HttpResponse(stream.getvalue())

3、登录接口里验证验证码是否正确

# 登录接口
@csrf_exempt
def tologin(request):
    data = request.POST.dict()
    print('用户输入内容', data)
    # 验证码的校验
    code = data['yzm']  # 前端输入的验证码
    _code = request.session.get('image_code', "")  # 获取验证码,没有就是空字符串
    print('正确验证码', _code)
    if _code == "":
        return HttpResponse(json.dumps({
            'code': 203,
            'msg': '验证码已过期'
        }))
    if _code.upper() == code.upper():  # upper是全部变为大写字母
        pass
    elif code == 'xczx': # 万能验证码
        pass
    else:
        return HttpResponse(json.dumps({
            'code': 202,
            'msg': '验证码错误'
        }))

4、前端界面,存放验证码,src 填写 请求接口

<img class="yzm_img" src="/image/code/" @click="get_code">

5、点击图片,切换验证码

get_code() {
                $.ajax({
                    method: "POST",
                    // async: false, // 将异步变为同步, 默认 为异步,true
                    url: "/image/code/", // 接口
                    // contentType: "application/json", // json格式
                    // dataType: "jsonp", //跨域json请求一定是jsonp
                    // jsonp: "callbackparam", //跨域请求的参数名,默认是callback
                    // headers: {
                    //     "Authorization": localStorage.getItem("mytoken") //此处放置请求到的用户token
                    // },


                    // 传给后台的数据
                })
                    .done((res) => {
                        $('.yzm_img').attr('src', src = "/image/code/" + "?t=" + Math.random()) // 验证码图片名称不变,加入一个随机字符串


                    })
                    .fail((err) => {
                        console.log(err)
                    });
                console.log('重置验证码')
            }

 

posted @ 2022-07-07 16:33  彬彬有礼丶林  阅读(84)  评论(0编辑  收藏  举报