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('重置验证码') }