基于django实现图文验证码两种方式
引言:无论做什么项目用户模块永远绕不开的坎,而用户模块貌似一定是有验证码的,这里介绍python下两种实现验证码的方式
环境介绍:django+python3.6以上版本
方式1:使用django自带的django-simple-captcha
-
第三方包的下载
pip install django-simple-captcha
-
将captcha安装到 install_apps里面
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'captcha', ]
-
在主路由配置captcha应用的路由
urlpatterns = [ path('admin/', admin.site.urls), path('captcha/',include('captcha.urls')), ]
-
迁移同步,生成captcha所依赖的表
#生成迁移脚本 python manage.py makemigrations #执行文件迁移 python manage.py migerte ''' 如果出现错误可以尝试执行执行第二条命令,或者在两条命令后加上app名 python manage.py makemigrations captcha python manage.py migerte captcha '''
-
将captcha字段在form类当中进行设置
#例子:forms.py from django import forms from captcha.fields import CaptchaField class UserRegisterForm(forms.Form): email = forms.EmailField(required=True) password = forms.CharField(required=True,min_length=6,max_length=26,error_messages={ 'required':'密码不能为空', 'min_length': '密码至少6个字符', 'max_length' : '密码过长', }) captcha = CaptchaField()
-
在后台逻辑当中,get请求里面实例化我们的form,将form对象返回到页面
#views.py 代码逻辑 def user_register(request): if request.method == 'GET': #实例化user_register_form 不是为了验证,而是为了使用验证码 user_register_form = UserRegisterForm() return render(request,'register.html',{'user_register_form':user_register_form}) else: pass
-
在页面上 获取验证码以下是注册页中部分代码
<div class="form-group marb8 captcha1 "> <label>验 证 码</label> {{ user_register_form.captcha }} </dv>
-
打开注册页面发送get请求得到需要的效果,且点击会刷新验证码
方式2:自己动手丰衣足食,自己画验证码
python为我们提供了额外的第三方画图库
使用须知
- 熟练使用django框架
- 熟练使用html超文本标记语言
- 会使用ajax配置后台逻辑
实现原理
- 通过PIL绘制图片(可定义字符,图片大小,辨别障碍...)
- 前端展示图片
- 用户提交验证码,通过ajax将信息发送至前台进行对比
- 点击图片刷新(通过传递不同的数据来展示不同的图片)
不多BB直接上代码
#views.py
#views
from PIL import Image, ImageDraw, ImageFont
from random
def verify_code(request):
# 引入随机函数模块
import random
def rndColor():
"""
生成随机颜色
:return:
"""
return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))
# 定义变量,用于画面的背景色、宽、高
bgcolor = (rndColor())
width = 100
height = 37
# 创建画面对象
im = Image.new('RGB', (width, height), bgcolor)
# 创建画笔对象
draw = ImageDraw.Draw(im)
# 调用画笔的point()函数绘制噪点
for i in range(0, 100):
xy = (random.randrange(0, width), random.randrange(0, height))
fill = (random.randrange(0, 255), 255, random.randrange(0, 255))
draw.point(xy, fill=fill)
# 定义验证码的备选值
str1 = 'ABCD123EFGHIJK456LMNOPQRS789TUVWXYZ0'
# 随机选取4个值作为验证码
rand_str = ''
for i in range(0, 4):
rand_str += str1[random.randrange(0, len(str1))]
# 构造字体对象,ubuntu的字体路径为“/usr/share/fonts/truetype/freefont”
font = ImageFont.truetype('simhei.ttf', 23)
# 构造字体颜色
fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255))
# 绘制4个字
draw.text((5, 2), rand_str[0], font=font, fill=fontcolor)
draw.text((25, 2), rand_str[1], font=font, fill=fontcolor)
draw.text((50, 2), rand_str[2], font=font, fill=fontcolor)
draw.text((75, 2), rand_str[3], font=font, fill=fontcolor)
# 写干扰圆圈
for i in range(40):
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(5):
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())
# 释放画笔
del draw
# 存入session,用于做进一步验证
request.session['verifycode'] = rand_str
# 内存文件操作
buf = BytesIO()
# 将图片保存在内存中,文件类型为png
im.save(buf, 'png')
# 将内存中的图片数据返回给客户端,MIME类型为图片png
return HttpResponse(buf.getvalue(), 'image/png')
#将验证码的数据其实是存储到session中通过session和前端获取的值进行比较
#因为要忽视大小写,这里用.lower(),全部转换为小写进行比较
def verify_yz(request):
'''验证码校验视图'''
user_yzm = request.GET.get('user_yzm')
verifycode = request.session['verifycode']
print('user_yzm='+user_yzm)
print('verifycode='+verifycode)
if user_yzm.lower() == verifycode.lower():
return restful.ok("OK", data=None)
else:
return restful.params_error("验证码错误", data=None)
#html
#输入验证码
<input type="text" name="user_yzm" id='user_yzm' class="user_yzm" placeholder="请输入图文验证">
#盒子内放置图片
<div id="photo_yzm">
<img id="yzm" class="yzm" src="/user/verify_code"/>//也可以写成:src="{% url 'user:verify_code' %}"
</div>
#实现点击验证码图片进行刷新的js代码
<script type="text/javascript" src="{% static 'js/jquery-1.12.4.min.js'%}"></script>
<script type="text/javascript" src="{% static 'js/register.js' %}"></script>
//ajax
<script>
$(function(){
var img = $('#yzm');
//点击图片触发事件
img.click(function(){
//获取现在时间,用于每次刷新图片不同
mydate=new Date();
//点击却换yzm的src属性.后面加参数是因为每次访问网站之后每次参数不同接收到的图像也不同,如果没有传参数,每次返回的都是相同的图像
$(this).attr("src",'/user/verify_code?a='+mydate);
});// img click
var photo_text = $('.user_yzm');
//验证码图片改变事件
photo_text.change(function(){
//ajax
var user_yzm = $(this).val();
{#alert(user_yzm);#}
$.ajax({
//获取方式,这边写get,views获取也要写get,所连接到的是本文views中71行,使用POST出现问题请看:https://blog.csdn.net/weixin_43790705/article/details/87867172
type: "get",
//将数据发送到:
url: "{% url 'user:verify_yz' %}",
//数据
data:"user_yzm="+user_yzm,
//数据类型默认为json
success: function(msg){
{#alert('发送ajax');#}
{#obj = eval("("+msg+")");#}
alert(msg.code);
//如果返回的参数的code属性为200那么执行:
if(msg.code=='200'){
$('#user_yzm').css({"background": "rgba(87,255,53,0.51)"});
}
//否则
else{
$('#user_yzm').css({"background": "rgba(255,113,103,0.47)"});
}
}
})// ajax
}) //change
})// $func
</script>