WEB开发-动态验证码
1.基于Python实现,用到了django后台处理,刷新验证码功能,其他语言大同小异
2.登录界面
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content=""> <title>DevOPS v1.0</title> <!-- Bootstrap Core CSS --> <link href="/static/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet"> <!-- MetisMenu CSS --> <link href="/static/vendor/metisMenu/metisMenu.min.css" rel="stylesheet"> <!-- Custom CSS --> <link href="/static/dist/css/sb-admin-2.css" rel="stylesheet"> <!-- Custom Fonts --> <link href="/static/vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css"> <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script> <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script> <![endif]--> </head> <body> <div class="container"> <div class="row"> <div class="col-md-4 col-md-offset-4"> <div class="login-panel panel panel-default"> <div class="panel-heading"> <h3 class="panel-title">Please Sign In</h3> </div> <div class="panel-body"> <form role="form" action="/index/login/" method="post"> <fieldset> <div class="form-group"> <input class="form-control" placeholder="Username" name="username" type="text" autofocus> </div> <div class="form-group"> <input class="form-control" placeholder="Password" name="password" type="password" value=""> </div> <div class="form-group"> <input class="form-control" placeholder="验证码" name="yanzhengma" type="text" value=""> {# <span><img src={{ data }}></span>#} {# <span>{{ data }}</span>#} <img src="/index/yanzhengma/" onclick="ChangeCode(this);"/> <div style="color: red;">{{ msg }}</div> </div> <div class="checkbox"> <label> <input name="remember" type="checkbox" value="Remember Me">Remember Me </label> </div> <!-- Change this to a button or input when using this as a form --> {# <a href="/login/" class="btn btn-lg btn-success btn-block">Login</a>#} <input type="submit" class="btn btn-lg btn-success btn-block" name="Login"/> </fieldset> </form> </div> </div> </div> </div> </div> <!-- jQuery --> <script src="/static/vendor/jquery/jquery.min.js"></script> <!-- Bootstrap Core JavaScript --> <script src="/static/vendor/bootstrap/js/bootstrap.min.js"></script> <!-- Metis Menu Plugin JavaScript --> <script src="/static/vendor/metisMenu/metisMenu.min.js"></script> <!-- Custom Theme JavaScript --> <script src="/static/dist/js/sb-admin-2.js"></script> <script type="text/javascript"> function ChangeCode(ths) { var src_re = $(ths).attr('src'); $(ths).attr('src', src_re + '?'); } </script> </body> </html>
里面涉及到2个后端视图函数login和get_yanzhengma
3.后端视图函数
helper.py
# -*- coding=utf-8 -*- import random # 随机字母: def rndChar(): return chr(random.randint(65, 90)) + chr(random.randint(65, 90)) + chr(random.randint(65, 90)) + chr(random.randint(65, 90))
Django的views.py
# -*- coding=utf-8 -*- ############################## from django.shortcuts import render, HttpResponse, render_to_response,redirect from app import models from helper import rndChar from PIL import Image, ImageFont, ImageDraw import io # Create your views here. def index(request): # return HttpResponse('123456') return render_to_response('app/pages/index.html') def login(request): if request.method == 'POST': print request.POST username = request.POST.get('username',None) password = request.POST.get('password',None) yanzhengma = request.POST.get('yanzhengma',None) # print yanzhengma,request.session['yanzhengma'] if yanzhengma.upper() != request.session['yanzhengma'].upper(): return render_to_response('app/pages/login.html',{'msg':'验证码错误'}) count = models.AdminInfo.objects.filter(username=username,password=password).count() if count > 0: request.session['is_login'] = {'user':username} return redirect('/index/') # return render_to_response('app/pages/index.html') else: return render_to_response('app/pages/login.html',{'msg':'账户密码错误'}) else: # print stream.getvalue() # im.save("static/image/t.png") # request.session['yanzhengma'] = text return render_to_response('app/pages/login.html',{'msg':''}) def yanzhengma(request): #text为产生的4位随机字符串 text = rndChar() # print text request.session['yanzhengma'] = text #图片处理程序,将文本做成图片 im = Image.new("RGB", (130, 35), (255, 255, 255)) dr = ImageDraw.Draw(im) font = ImageFont.truetype("arial", 24) # simsunb.ttf 这个从windows fonts copy一个过来 dr.text((10, 5), text, font=font, fill="#000000") # im.show() #创建一个io对象 stream = io.BytesIO() #将图片对象im保存到stream对象里 im.save(stream, "png") #stream.getvalue()图片二级制内容,再通过HttpResponse封装,返回给前端页面 return HttpResponse(stream.getvalue())
4.效果图展示
5.备注:
(1)img标签的src属性,去这个/get_yanzhengma/去取图片
(2)get_yanzhengma函数执行
(3)通过random模块生成随机码,4个字母
(4)通过PIL模块将随机数字转换为图片对象im
(5)创建一个BytesIO对象,内存对象,可以存储二进制的东西
(6)将图片对象保存到BytesIO对象中,此处在内存里
#话说为什么要将图片对象保存到BytesIO对象中而不是直接写到硬盘里存为图片文件呢?因为这样就保证了在同一个时刻,不同用户访问到的验证码是不一样的,而且都是存储在内存中的。
#如果写成验证码图片文件到硬盘里,有可能B页面显示的验证码是ABCD,但是B用户还没提交,A用户这会访问,刷新了验证码,把验证码变更为DCBA了,B页面里看到的还是ABCD,导致一直输不对验证码;无法保证2个用户的验证码图片冲突问题
#后端验证码的随机值是存储在session中的,每次用户GET请求,服务器上生成随机验证码存储在session中,并给页面返回,如果用户提交的验证码和后端session中记录的一致通过,如果不一致,重新刷新验证码,用户重新进行提交
(7)BytesIO对象的getvalue()方法返回二进制内容
(8)django提供的HttpResponse封装二进制内容为识别的东西传递给前端
(7)前端img标签正常显示图片
(9)用户点击图片,js先获取到这个图片标签,取到当前的src属性值存为变量src_re,然后更改src的属性值为src_re + ?
#为什么要加?呢是因为GET请求,每最后加一个?代表一个新的url,但是效果呢是和/index/yanzhengma/是一致的,每点一次,后面加一个?。/index/yanzhengma/? /index/yanzhengma/??这个意思
#如果每次只更改src的属性值为/index/yanzhengma/的话,不会进行request请求,会直接浏览器缓存读取。达不到刷新验证码的目的