captcha.py
import os
import io
import string
import random
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
from django.conf import settings
class Captcha:
CAPTCHA_THRESHOLD = 3 # 需要输入验证码的阈值
CAPTCHA_EXPIRED = 60 * 5 # 过期时间,second
CAPTCHA_SIZE = 4 # 长度
CAPTCHA_ALLOWED_CHARS = string.ascii_lowercase # 可用字符
def __init__(self):
...
def gen_captcha_code(self):
"""生成图形验证码代码"""
return ''.join([random.choice(self.CAPTCHA_ALLOWED_CHARS) for _ in range(self.CAPTCHA_SIZE)])
def gen_captcha(self):
"""生成图形验证码"""
font_size = 30
space = 10
line_density = 10 # 干扰线密度
point_density = 1000 # 噪点密度
width = (font_size + space) * self.CAPTCHA_SIZE + space
height = font_size + space * 2
code = self.gen_captcha_code()
random_color = lambda: random.randint(0, 200), random.randint(0, 200), random.randint(0, 200)
random_light_color = lambda: random.randint(200, 255), random.randint(200, 255), random.randint(200, 255)
random_point = lambda: random.randint(0, width), random.randint(0, height)
# 创建画布
img = Image.new('RGB', (width, height), random_light_color())
draw = ImageDraw.Draw(img)
# 噪点
for _ in range(point_density):
draw.point(random_point(), fill=random_color())
# 干扰线
for _ in range(line_density):
draw.line([random_point(), random_point()], fill=random_color())
# 验证码
font_path = os.path.join(settings.BASE_DIR, 'administrator/static/administrator/fonts/Vera.ttf')
font = ImageFont.truetype(font_path, font_size)
for i in range(settings.CAPTCHA_SIZE):
draw.text(((font_size + space) * i + space, space / 2), code[i], font=font, fill=random_color())
# 模糊处理
# img = img.filter(ImageFilter.BLUR)
buf = io.BytesIO()
img.save(buf, 'gif')
return ''.join(code), buf.getvalue()
登录方法
def login():
#逻辑忽略
captcha, img = gen_captcha()
#将二进制数据转base64传给前端
data={
'captcha':base64.b64encode(img).decode('utf-8')
}
return jsonResponse(data)
前端 vue
<div class="layui-form-item" id="captcha_box" v-if="showCaptcha" v-cloak>
<div class="layui-row">
<div class="layui-col-xs7">
<label class="layadmin-user-login-icon layui-icon layui-icon-vercode" for="LAY-user-login-vercode"></label>
<input type="text" name="vercode" placeholder="图形验证码" class="layui-input" v-model="captcha" @keyup.enter="login" />
</div>
<div class="layui-col-xs5">
<div style="margin-left: 10px">
<img :src="captcha_src" class="layadmin-user-login-codeimg" @click="login('code')" />
</div>
</div>
</div>
</div>
login: function (str) {
$.ajax({
url: login_url,
type: 'POST',
dataType: 'json',
data: {
adminname: this.username,
password: this.password,
captcha: this.captcha,
keep_logined: this.remember
},
success: function (res) {
if (!res.code) {
localStorage.setItem('login-id', res.data.admin_id);
localStorage.setItem('login-user', res.data.nickname);
localStorage.setItem('login-safety', parseInt(res.data.safety));
localStorage.setItem('login-method', login_method);
window.location.href = 'index.html';
} else {
if (res.data.captcha) {
vue.captcha_src = 'data:image/gif;base64,' + res.data.captcha;
vue.showCaptcha = true;
if (str !== 'code') layer.msg('错误:' + res.msg, {icon: 2});
} else {
layer.msg('错误:' + res.msg, {icon: 2});
}
}
}
});
},