随机验证码图片的实现

Django实现随机验证码图片

现在,每当我们在进行登录的时候,所有网站几乎都会让用户填写验证码,效果如下图所示:

本文就为大家讲一下用Django如何实现“随机验证码图片”的。

前端渲染

前端我们需要一个用户输入框以及存放随机验证码图片的img标签
<div class="form-group">
    <label for="valid_code">验证码</label>
    <div class="row">
        <div class="col-md-6">
            <input type="text" id="valid_code" class="form-control">
        </div>
        <div class="col-md-6">
            <img id="valid_code_img" src="/get_validCode_img/" width="260px" height="35px" alt="">
        </div>
    </div>
</div>
注意这里img的高度是35px,宽度是260px——后面需要注意这个参数。
在img标签中我们写了一个src="/get_validCode_img/"的链接,对应到路由中的写法:
re_path(r'^get_validCode_img/$', views.get_validCode_img),
为了实现解耦我们的视图函数中只有调用其他模块:
def get_validCode_img(request):
	##引入获取随机验证码图片的模块
	from blog.utils.valid_code import get_valid_code_img
	##data获取
	data = get_valid_code_img(request)
	##返回
	return HttpResponse(data)
可想而知,我们的核心代码在get_valid_code_img函数中!

实现随机验证码图片的完整代码

这里先给出完整版代码,下面进行一一详解
import random

##获取三个随机数,用于“颜色的调配”
def get_random_color():
    return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))

def get_valid_code_img(request):
    ###基于PIL模块动态生成状态码图片
    ##引入相应模块
    from PIL import Image, ImageDraw, ImageFont
    from io import BytesIO

    ##这个大小跟前端的img大小要一致
    img = Image.new('RGB', (260, 35), color=get_random_color())
    draw = ImageDraw.Draw(img)
    ##字体对象,字体大小为32
    font_obj = ImageFont.truetype('static/font/bmwy.ttf', size=28)

    ##随机获取5位的数字字母的组合
    valid_code_str = ''
    for i in range(5):
        random_num = str(random.randint(0, 9))
        random_low_alpha = chr(random.randint(97, 122))
        random_upper_alpha = chr(random.randint(65, 90))
        random_char = random.choice([random_num, random_upper_alpha, random_low_alpha])
        draw.text((i * 50 + 20, 5), random_char, get_random_color(), font=font_obj)
        ##保存验证码字符串
        valid_code_str += random_char
    
    ##噪点噪线
    width = 260
    height = 35
	##改变range的值可以增加或减少噪点噪线的多少
    for i in range(11):
        x1 = random.randint(10,width)
        x2 = random.randint(10,width)
        y1 = random.randint(10,height)
        y2 = random.randint(10,height)
        draw.line((x1,x2,y1,y2),fill=get_random_color())
    for i in range(30):
        draw.point([random.randint(0,width),random.randint(0,height)],fill=get_random_color())
        x = random.randint(0,width)
        y = random.randint(0,height)
        draw.arc((x,y,x+14,y+14),0,90,fill=get_random_color())
    
    ##将随机字符串存在session里——再在login()中提取!
    ##这部分十分重要!要知道三个详细的流程
    request.session['valid_code_str'] = valid_code_str
	##保存
    f = BytesIO()
    img.save(f, 'png')
    data = f.getvalue()

    return data

具体实现介绍

实现随机验证码图片的核心模块时PIL模块,我们可以将这个过程分解为如下几步:一是为我们随机验证码找到一个空间,而这个空间的大小正好应该跟我们前端img标签的大小匹配上,这也就是为什么在前端渲染的时候特意给大家强调了下关注img标签的大小;第二步就是在我们提供的这个空间上进行背景颜色以及字体等设置;第三就是利用程序得到我们需要的“随机验证码”;接着就是将得到的这个“随机验证码”写入之前提供好的“空间”中去。最后将这个写好随机验证码的图片存入内存即可。
结合上面的讲解与自己的体验,聪明的你可能会提出下面几个问题:
一、我们做这个“随机验证码”的目的是“验证”,得到的图片并不是最终的目的!在实际中我们需要对用户的输入与我们生成的“随机验证码”去匹配,匹配成功后再进行用户名以及密码的匹配,如果两个地方都匹配正确了才显示登陆成功。
二、生成的随机验证码图片对人来说很好识别,那么对于机器爬取也是很简单的一件事情,我们如何做去避免机器爬取生成的图片里的数据呢?
三、如果由于字体问题用户“猜”不出来图中的字母是什么了,有没有办法实现“点击图片自动刷新验证码”呢?
一:对于第一个问题,我们可以利用session解决,如前面的代码所示,将最终的“随机验证码”valid_code_str保存在session中——request.session['valid_code_str'] = valid_code_str,而我们在登陆验证的视图函数中既可以取到用户输入的随机验证码的值,又可以在session中通过 request.session.get('valid_code_str')方法拿到系统随机生成的随机验证码,将这两个值进行比对(如果不想区分大小写可以将得到的值先upper后再比对)即可。
二:为了防止程序的“爬取”,我们可以在生成的图片上加上噪点噪线,如上面的“噪点噪线”代码所示,效果如下:

三:对于点击刷新图片验证码可以在模板中加一个click事件,修改下src属性即可:
 //点击刷新图片验证码
$('#valid_code_img').click(function () {
    $(this)[0].src += '?'
});

关于滑动验证码

其实现在玩的比较高端的是“滑动验证码”,从安全性与复杂度来讲都要优于我们的“验证码图片”,关于滑动验证码如果大家有兴趣的话可以看我在github上传的项目(基于Django1.8版本的,当然我在django2.0打开也可以用)注意下载里面的名字是django_demo的项目

https://github.com/Wanghongw/django_practice

posted on 2018-09-19 21:44  江湖乄夜雨  阅读(1688)  评论(0编辑  收藏  举报