Django 验证码
第一部分:第三方库django-simple-captcha
前提条件:
-
安装pip install django-simple-captcha, pip install Pillow
-
将captcha 加入 settings.py 的 INSTALLED_APPS
-
运行python manager.py migrations 和 python manage.py migrate
-
url路由加入urls.py的urlpatterns
url(r'^captcha/', include('captcha.urls')) # 这是生成验证码的图片
1、创建Forms
from django import forms
from captcha.fields import CaptchaField
class CaptchaForm(forms.Form):
username = forms.CharField(max_length=100, label='username')
password = forms.FloatField(max_value=100, label='password')
captcha = CaptchaField(error_messages={"invalid": u"验证码错误"}) # 为生成的验证码图片,以及输入框
2、Views逻辑
class RegisterView(View):
def get(self, request):
register_form = CaptchaForm() # 实例化CapatchaForm
return render(request, "register.html", locals())
def post(self, request):
register_form = CaptchaForm(request.POST) # 实例化CapatchaForm
if register_form.is_valid():
username = request.POST.get("username", "")
password = request.POST.get("password", "")
User.objects.create(username=username, password=make_password(password))
return render(request, "register_success.html")
else:
return render(request, "register.html", locals())
3、HTML代码
<form class="form-signin" action="{% url "register" %}" method="post">
<h2 class="form-signin-heading">Register</h2>
<label for="recipient-name" class="control-label">Username:</label>
<input type="text" class="form-control" name="username" placeholder="Username" required autofocus>
<label for="recipient-name" class="control-label">Password:</label>
<input type="password" class="form-control" name="password" placeholder="Password" required>
<label for="recipient-name" class="control-label">Captcha:</label>
{{ register_form.captcha }}
<button class="btn btn-lg btn-primary btn-block" type="submit">Register</button>
{% csrf_token %}
</form>
4、JQuery代码(实现验证码刷新)
<script>
// 添加样式
$(function(){
$(".captcha").css({
"cursor": "pointer"
});
$("#id_captcha_1").addClass("form-control")
});
// ajax刷新验证码
$(".captcha").click(function () {
$.getJSON("/captcha/refresh/",
function (result) {
$(".captcha").attr("src", result["image_url"]);
$("#id_captcha_0").val(result['key'])
});
});
</script>
最终效果:
第二部分:自己写Django验证码
前提条件:
-
安装pip install Pillow
- Monaco.ttf字体文件
- BytesI
""" 生成验证码功能; 使用方法: def code(request): from io import BytesIO() img_obj, code = create_validate_code() stream = BytesIO() img_obj.save(stream, 'png') request.session['check_code'] = code return HttpResponse(stream.getvalue()) """ import random from PIL import Image, ImageDraw, ImageFont, ImageFilter # pip3 install Pillow _letter_cases = "abcdefghjkmnpqrstuvwxy" # 小写字母,去除可能干扰的i,l,o,z _upper_cases = _letter_cases.upper() # 大写字母 _numbers = ''.join(map(str, range(0, 10))) # 数字 init_chars = ''.join((_letter_cases, _upper_cases, _numbers)) def create_validate_code(size=(120, 30), chars=init_chars, mode="RGB", bg_color=(255, 255, 255), fg_color=(0, 0, 255), font_size=18, font_type="Monaco.ttf", length=4, draw_lines=True, n_line=(1, 2), draw_points=True, point_chance=2): ''' @todo: 生成验证码图片 @param size: 图片的大小,格式(宽,高),默认为(120, 30) @param chars: 允许的字符集合,格式字符串 @param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG @param mode: 图片模式,默认为RGB @param bg_color: 背景颜色,默认为白色 @param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF @param font_size: 验证码字体大小 @param font_type: 验证码字体,默认为 ae_AlArabiya.ttf @param length: 验证码字符个数 @param draw_lines: 是否划干扰线 @param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效 @param draw_points: 是否画干扰点 @param point_chance: 干扰点出现的概率,大小范围[0, 100] @return: [0]: PIL Image实例 @return: [1]: 验证码图片中的字符串 ''' width, height = size # 宽, 高 img = Image.new(mode, size, bg_color) # 创建图形 draw = ImageDraw.Draw(img) # 创建画笔 def get_chars(): '''生成给定长度的字符串,返回列表格式''' return random.sample(chars, length) def create_lines(): '''绘制干扰线''' line_num = random.randint(*n_line) # 干扰线条数 for i in range(line_num): # 起始点 begin = (random.randint(0, size[0]), random.randint(0, size[1])) #结束点 end = (random.randint(0, size[0]), random.randint(0, size[1])) draw.line([begin, end], fill=(0, 0, 0)) def create_points(): '''绘制干扰点''' 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)) def create_strs(): '''绘制验证码字符''' c_chars = get_chars() strs = ' %s ' % ' '.join(c_chars) # 每个字符前后以空格隔开 font = ImageFont.truetype(font_type, font_size) font_width, font_height = font.getsize(strs) draw.text(((width - font_width) / 3, (height - font_height) / 3), strs, font=font, fill=fg_color) return ''.join(c_chars) if draw_lines: create_lines() if draw_points: create_points() strs = create_strs() # 图形扭曲参数 params = [1 - float(random.randint(1, 2)) / 100, 0, 0, 0, 1 - float(random.randint(1, 10)) / 100, float(random.randint(1, 2)) / 500, 0.001, float(random.randint(1, 2)) / 500 ] img = img.transform(size, Image.PERSPECTIVE, params) # 创建扭曲 img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 滤镜,边界加强(阈值更大) return img, s
Identify Code代码

""" 生成验证码功能; 使用方法: def code(request): from io import BytesIO() img_obj, code = create_validate_code() stream = BytesIO() img_obj.save(stream, 'png') request.session['check_code'] = code return HttpResponse(stream.getvalue()) """ import random from PIL import Image, ImageDraw, ImageFont, ImageFilter # pip3 install Pillow _letter_cases = "abcdefghjkmnpqrstuvwxy" # 小写字母,去除可能干扰的i,l,o,z _upper_cases = _letter_cases.upper() # 大写字母 _numbers = ''.join(map(str, range(0, 10))) # 数字 init_chars = ''.join((_letter_cases, _upper_cases, _numbers)) def create_validate_code(size=(120, 30), chars=init_chars, img_type="GIF", mode="RGB", bg_color=(255, 255, 255), fg_color=(0, 0, 255), font_size=18, font_type="Monaco.ttf", length=4, draw_lines=True, n_line=(1, 2), draw_points=True, point_chance=2): ''' @todo: 生成验证码图片 @param size: 图片的大小,格式(宽,高),默认为(120, 30) @param chars: 允许的字符集合,格式字符串 @param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG @param mode: 图片模式,默认为RGB @param bg_color: 背景颜色,默认为白色 @param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF @param font_size: 验证码字体大小 @param font_type: 验证码字体,默认为 ae_AlArabiya.ttf @param length: 验证码字符个数 @param draw_lines: 是否划干扰线 @param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效 @param draw_points: 是否画干扰点 @param point_chance: 干扰点出现的概率,大小范围[0, 100] @return: [0]: PIL Image实例 @return: [1]: 验证码图片中的字符串 ''' width, height = size # 宽, 高 img = Image.new(mode, size, bg_color) # 创建图形 draw = ImageDraw.Draw(img) # 创建画笔 def get_chars(): '''生成给定长度的字符串,返回列表格式''' return random.sample(chars, length) def create_lines(): '''绘制干扰线''' line_num = random.randint(*n_line) # 干扰线条数 for i in range(line_num): # 起始点 begin = (random.randint(0, size[0]), random.randint(0, size[1])) #结束点 end = (random.randint(0, size[0]), random.randint(0, size[1])) draw.line([begin, end], fill=(0, 0, 0)) def create_points(): '''绘制干扰点''' 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)) def create_strs(): '''绘制验证码字符''' c_chars = get_chars() strs = ' %s ' % ' '.join(c_chars) # 每个字符前后以空格隔开 font = ImageFont.truetype(font_type, font_size) font_width, font_height = font.getsize(strs) draw.text(((width - font_width) / 3, (height - font_height) / 3), strs, font=font, fill=fg_color) return ''.join(c_chars) if draw_lines: create_lines() if draw_points: create_points() strs = create_strs() # 图形扭曲参数 params = [1 - float(random.randint(1, 2)) / 100, 0, 0, 0, 1 - float(random.randint(1, 10)) / 100, float(random.randint(1, 2)) / 500, 0.001, float(random.randint(1, 2)) / 500 ] img = img.transform(size, Image.PERSPECTIVE, params) # 创建扭曲 img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 滤镜,边界加强(阈值更大) return img, strs
Djaong中调用代码

class LoginView(View): def get(self, request): return render(request, "login.html") def post(self, request): code = request.POST.get("code") if code.upper() == request.session['identify_code'].upper(): username = request.POST.get("username", "") password = request.POST.get("password", "") user_obj = UserInfo.objects.filter(username=username, password=password).first() if user_obj: request.session["is_login"] = True request.session["user_info"] = {"user_id": user_obj.nid, "user_name": user_obj.username} return redirect(reverse("index")) return render(request, "login.html", {'msg': "验证码错误"}) class IdentifyCodeView(View): """ 验证码生成视图 """ def get(self, request): img_obj, code = create_validate_code() stream = BytesIO() img_obj.save(stream, 'png') request.session['identify_code'] = code return HttpResponse(stream.getvalue())
HTML代码

<!DOCTYPE html> {% load staticfiles %} <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> #code{ cursor: pointer; } </style> </head> <body> <div> <form action="{% url "login" %}" method="post"> <div><input type="text" name="username"></div> <div><input type="password" name="password"></div> <div><input type="text" name="code"><img src="{% url "identify_code" %}" id="code"></div> <div>{{ msg }}</div> <div><input type="submit" value="提交"></div> {% csrf_token %} </form> </div> </body> <script src="{% static "js/jquery-3.2.1.js" %}"></script> <script> $("#code").click(function () { $(this)[0].src = $(this)[0].src + "?"; }) </script> </html>