柴少的博客 也许终将一事无成,却不能甘于平庸。

Django之验证码(十六)

一、验证码原理

第一次访问GET,后台:

  1. 创建一张图片

  2. 在图片中写入随机字符串

  3. 将图片写到指定文件

  4. 打开指定目录文件,读取内容

  5. 把生成的验证码保存在session中

  6. 通过HttpResponse()把图片反馈给前端

提交POST: 获取用户提交的POST和session的验证码比较。

1.1 先来一个小例子:

urls.py:

url(r'^success/$', views.success),
url(r'^login_ajax/$', views.login_ajax),
url(r'^login_ajax_check/$', views.login_ajax_check),
url(r'^verify_code/$', views.verify_code),
url(r'^post_article/$', views.post_article),

views.py :

from PIL import Image, ImageDraw, ImageFont   #PIL是python2版本的图像处理库,不过现在用Pillow比PIL强大,是python3的处理库
from django.http import JsonResponse
from django.shortcuts import render, redirect
import random
from io import BytesIO   #在python3.x中,StringIO已经在io模块中了,导入方法

#ajax登录视图函数
def login_ajax(request):
    return render(request,'login_ajax.html')
    
#ajax登录校验回调视图函数    
def login_ajax_check(request):
    uname = request.POST.get('uname')   #获取用户输入的用户名和密码
    password = request.POST.get('password') 
    vcode = request.POST.get('vcode')  #获取用户输入的验证码
    vcode_session = request.session.get('verifycode')  #获取session中的验证码
    #用户名和密码校验
    if uname == 'root' and password == '123456' and vcode == vcode_session:
        #保存用户的登录状态
        request.session['isLogin'] = True
        request.session['uname'] = uname
        request.session['password'] = password
        return JsonResponse({'msg': 'ok'})
    elif uname != 'root' or password != '123456':
        return JsonResponse({'msg': 'fail_user'})
    elif vcode != vcode_session:
        return JsonResponse({'msg': 'fail_verify'})
        
def verify_code(request):
    #定义变量,用于画面的背景色、宽、高
    bgcolor = (random.randrange(20, 100), random.randrange(
        20, 100), 255)
    width = 100
    height = 25
    #创建画面对象
    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('FreeMono.ttf', 23)  #这里可能会导致报错找不到这个字体,所以如果报错改为下面的字体
    font = ImageFont.truetype('arial.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)
    #释放画笔
    del draw
    #存入session,用于做进一步验证
    request.session['verifycode'] = rand_str
    """
    python2的为
    # 内存文件操作
    import cStringIO
    buf = cStringIO.StringIO()
    """
    # 内存文件操作-->此方法为python3的
    import io
    buf = io.BytesIO()  #内存文件操作
    #将图片保存在内存中,文件类型为png
    im.save(buf, 'png')
    #将内存中的图片数据返回给客户端,MIME类型为图片png
    return HttpResponse(buf.getvalue(), 'image/png')

# ajax登录成功视图函数
def success(request):
    # 用户已经登录
    if request.session.get('isLogin'):
        return render(request, 'sucess.html')
    else:
        return redirect('/login_ajax/')

# 发帖操作视图函数
def post_article(request):
    # 获取登录的用户名
    uname = request.session.get('uname')
    # 获取帖子的标题
    title = request.POST.get('title')
    content = request.POST.get('content')
    return HttpResponse('%s发了一篇名为%s的帖子:%s' % (uname.encode('utf-8').decode('utf-8'),
                        title.encode('utf-8').decode('utf-8'),content.encode('utf-8').decode('utf-8')))

login_ajax.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
    <style>
        #errorMsg {
            display: none;
            color: red;
        }
    </style>
</head>
<body>
<div>
    {% csrf_token %}
    用户名:<input type="text" id="uname"><br/>
    密&nbsp;&nbsp;码:<input type="password" id="password"><br/>

    验证码:<input type="text" id="vcode"/><br/>
    <!--直接调用生产图片验证码的视图函数,生产验证码-->
    <img src="/verify_code/" id="imgvcode"/><br/>

    <input type="button" value="登录" id="btnLogin"><br/>
    <div id="errorMsg"></div>
</div>
    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        $(function () {
            $('#btnLogin').click(function () {
                $('uname').reset;
                csrf = $('input').val();
                uname = $('#uname').val();
                password = $('#password').val();
                vcode = $('#vcode').val();
                //发起ajax请求,注意csrf攻击
                $.post('/login_ajax_check/', {
                    'csrfmiddlewaretoken': csrf,
                    'uname': uname,
                    'password': password,
                    'vcode': vcode,
                }, function (data) {
                    //获取返回的数据并进行操作
                    if (data.msg === 'ok') {
                        //登录成功
                        location.href = '/success/' //跳转到成功页面
                    } else if (data.msg === 'fail_user') {
                        $('#errorMsg').show().text('亲!用户名或密码错误!')

                    } else if (data.msg === 'fail_verify') {
                        //验证码错误
                        $('#errorMsg').show().text('亲!验证码错误!')
                    }
                })
            });
        });
    </script>
</body>
</html>

sucess.html :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录成功,发帖页面</title>
</head>
<body>
    <h2>亲!你登录成功了,欢迎你!!!</h2>
    <form method="post" action="/post_article/">
        {% csrf_token %}
        标题:<input type="text" name="title"/><br/>
        内容:<textarea name="content"></textarea><br/>
        <input type="submit" value="发帖"/>
    </form>
</body>
</html>

测试一把:

图片.png

#估计输错密码可以进行输入的验证。但是存在一个问题哈,你再点击验证码图片不发生变化了,还得重新刷新下页面。

图片.png

图片.png

图片.png

#点击发帖之后页面再跳转。

1.2 点击验证码刷新

图片.png

#上图是美团的验证码功能。

login_ajax.html:

$('#imgvcode').css('cursor', 'pointer').click(function () { //css('cursor', 'pointer')是让鼠标变成小手
     $('#imgvcode').attr('src', $("#imgvcode").attr('src')+'?1')  //找到验证码的id然后给其src所对应的url值加?1
});

#在原有的基础上增加原有的一段js。

图片.png

#上图可以看到还是有点问题的,每次url都累加,显然不想这么干。

再改进一把:

login_ajax.html:

<img src="/verify_code/" id="imgvcode"/><br/><span id="yzflush">看不清,换一张</span><br>  <!--显示验证码哪里稍微改一下,加个p标签-->
...
$('#yzflush').css('cursor', 'pointer').click(function () {
     srctag = $("#imgvcode").attr('src').split('?')[0]  //这个就是取到src的值然后以?为分割,取第一个值,这样就类似于每次重置一下url了。
     var myDate = new Date(); 
     $('#imgvcode').attr('src', srctag +'?'+ myDate.getTime())  //然后就是字段拼接了,myDate.getTime()就是把当前时间转换成精确到毫秒,这样保证url不会重复
});

图片.png

作者:chaishaopeng 分类:Django学习 浏览:961 评论:0
留言列表
发表评论
来宾的头像