Python生成随机验证码
一、安装依赖
CentOS
第一步:
1
|
yum install python - devel |
第二步:
yum install freetype-devel libjpeg-devel libpng-devel
1
2
|
sudo yum install libtiff - devel libjpeg - devel libzip - devel freetype - devel \ lcms2 - devel libwebp - devel tcl - devel tk - devel |
第三步:RPM包安装PIL
1
2
3
|
下载安装:ftp: / / rpmfind.net / linux / atrpms / f20 - x86_64 / atrpms / stable / PIL - 1.1 . 7 - 10.1 .fc20.x86_64.rpm 更多版本:http: / / rpmfind.net / linux / rpm2html / search.php?query = PIL&submit = Search + ...&system = &arch = |
Windows
第一步:
1
2
3
4
5
6
7
8
|
下载安装pip b. 解压,进入目录 c. 安装,Python setup.py install 注:安装过程中可能依赖setuptools,安装过程如下: 下载文件:https: / / bootstrap.pypa.io / ez_setup.py 执行文件:Python ez_setup.py |
第二步:
1
|
pip3 install Pillow |
二、使用
Python生成随机验证码,需要使用PIL模块.
1. 创建图片
1
2
3
4
5
6
7
8
9
|
from PIL import Image img = Image.new(mode = 'RGB' , size = ( 120 , 30 ), color = ( 255 , 255 , 255 )) # 在图片查看器中打开 # img.show() # 保存在本地 with open ( 'code.png' , 'wb' ) as f: img.save(f, format = 'png' ) |
2. 创建画笔,用于在图片上画任意内容
1
2
|
img = Image.new(mode = 'RGB' , size = ( 120 , 30 ), color = ( 255 , 255 , 255 )) draw = ImageDraw.Draw(img, mode = 'RGB' ) |
3. 画点
1
2
3
4
5
6
|
img = Image.new(mode = 'RGB' , size = ( 120 , 30 ), color = ( 255 , 255 , 255 )) draw = ImageDraw.Draw(img, mode = 'RGB' ) # 第一个参数:表示坐标 # 第二个参数:表示颜色 draw.point([ 100 , 100 ], fill = "red" ) draw.point([ 300 , 300 ], fill = ( 255 , 255 , 255 )) |
4. 画线
1
2
3
4
5
6
|
img = Image.new(mode = 'RGB' , size = ( 120 , 30 ), color = ( 255 , 255 , 255 )) draw = ImageDraw.Draw(img, mode = 'RGB' ) # 第一个参数:表示起始坐标和结束坐标 # 第二个参数:表示颜色 draw.line(( 100 , 100 , 100 , 300 ), fill = 'red' ) draw.line(( 100 , 100 , 300 , 100 ), fill = ( 255 , 255 , 255 )) |
5. 画圆
1
2
3
4
5
6
7
|
img = Image.new(mode = 'RGB' , size = ( 120 , 30 ), color = ( 255 , 255 , 255 )) draw = ImageDraw.Draw(img, mode = 'RGB' ) # 第一个参数:表示起始坐标和结束坐标(圆要画在其中间) # 第二个参数:表示开始角度 # 第三个参数:表示结束角度 # 第四个参数:表示颜色 draw.arc(( 100 , 100 , 300 , 300 ), 0 , 90 ,fill = "red" ) |
6. 写文本
1
2
3
4
5
6
|
img = Image.new(mode = 'RGB' , size = ( 120 , 30 ), color = ( 255 , 255 , 255 )) draw = ImageDraw.Draw(img, mode = 'RGB' ) # 第一个参数:表示起始坐标 # 第二个参数:表示写入内容 # 第三个参数:表示颜色 draw.text([ 0 , 0 ], 'python' , "red" ) |
7. 特殊字体文字
1
2
3
4
5
6
7
8
9
10
|
img = Image.new(mode = 'RGB' , size = ( 120 , 30 ), color = ( 255 , 255 , 255 )) draw = ImageDraw.Draw(img, mode = 'RGB' ) # 第一个参数:表示字体文件路径 # 第二个参数:表示字体大小 font = ImageFont.truetype( "kumo.ttf" , 28 ) # 第一个参数:表示起始坐标 # 第二个参数:表示写入内容 # 第三个参数:表示颜色 # 第四个参数:表示颜色 draw.text([ 0 , 0 ], 'python' , "red" , font = font) |
图片验证码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
import random def check_code(width = 120 , height = 30 , char_length = 5 , font_file = 'kumo.ttf' , font_size = 28 ): code = [] img = Image.new(mode = 'RGB' , size = (width, height), color = ( 255 , 255 , 255 )) draw = ImageDraw.Draw(img, mode = 'RGB' ) def rndChar(): """ 生成随机字母 :return: """ return chr (random.randint( 65 , 90 )) def rndColor(): """ 生成随机颜色 :return: """ return (random.randint( 0 , 255 ), random.randint( 10 , 255 ), random.randint( 64 , 255 )) # 写文字 font = ImageFont.truetype(font_file, font_size) for i in range (char_length): char = rndChar() code.append(char) h = random.randint( 0 , 4 ) draw.text([i * width / char_length, h], char, font = font, fill = rndColor()) # 写干扰点 for i in range ( 40 ): draw.point([random.randint( 0 , width), random.randint( 0 , height)], fill = rndColor()) # 写干扰圆圈 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()) img = img. filter (ImageFilter.EDGE_ENHANCE_MORE) return img,''.join(code) if __name__ = = '__main__' : # 1. 直接打开 # img,code = check_code() # img.show() # 2. 写入文件 # img,code = check_code() # with open('code.png','wb') as f: # img.save(f,format='png') # 3. 写入内存(Python3) # from io import BytesIO # stream = BytesIO() # img.save(stream, 'png') # stream.getvalue() # 4. 写入内存(Python2) # import StringIO # stream = StringIO.StringIO() # img.save(stream, 'png') # stream.getvalue() pass |
注意:字体文件下载,猛击这里
三、原理
from django.shortcuts import render,HttpResponse from django.http import JsonResponse from django.contrib import auth def login(request): # if request.method=="POST": if request.is_ajax(): user=request.POST.get("user") pwd=request.POST.get("pwd") validcode=request.POST.get("validcode") #获取用户输入的验证码 #Ajax请求返回一个字典 response={"user":None,"err_msg":""} if validcode.upper() == request.session.get("keep_str").upper(): #判断验证码是否对 user_obj=auth.authenticate(username=user,password=pwd) if user_obj: response["user"]=user else: response['err_msg']="用户名或者密码错误!" else: response["err_msg"]="验证码错误!" return JsonResponse(response) else: return render(request, "login.html") from PIL import Image, ImageDraw, ImageFont from io import BytesIO import random def get_valid_img(request): def get_random_color(): return (random.randint(0,255),random.randint(0,255),random.randint(0,255)) img = Image.new("RGB", (350, 38), get_random_color()) #新建一个图片对象 draw = ImageDraw.Draw(img) #根据图片对象新建一个文本对象 font = ImageFont.truetype("static/font/kumo.ttf", 32) #字体对象 keep_str = "" #验证码 for i in range(6): random_num = str(random.randint(0, 9)) #随机数字 random_lowalf = chr(random.randint(97, 122)) #随机小写字母 random_upperalf = chr(random.randint(65, 90)) #随机大写字母 random_char = random.choice([random_num,random_lowalf,random_upperalf]) draw.text((i*30+50,0),random_char, get_random_color(), font=font) #在图片上写入文本 keep_str += random_char # width = 350 # height = 38 # 在验证码图片上随机加10条线 # for i in range(10): # x1 = random.randint(0,width) # x2 = random.randint(0,width) # y1 = random.randint(0,height) # y2 = random.randint(0,height) # draw.line((x1,y1,x2,y2),fill=get_random_color()) # # 在验证码图片上随机加50个点 # for i in range(50): # 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 + 4, y + 4), 0, 90, fill=get_random_color()) # 写与读 f = BytesIO() #创建一块内存空间 img.save(f, "png") #将图片保存到内存中 data = f.getvalue() #读取图片 # 将验证码存在各自的session中 request.session['keep_str'] = keep_str return HttpResponse(data)
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css"> </head> <body> <h3>登录页面</h3> <div class="container"> <div class="row"> <div class="col-md-8 col-md-offset-2"> <form action="" method="post"> {% csrf_token %} <div class="form-group"> <label for="">用户名</label> <input type="text" class="form-control" id="user"> </div> <div class="form-group"> <label for="">密码</label> <input type="password" class="form-control" id="pwd"> </div> <div class="form-group"> <label for="">验证码</label> <div class="row"> <div class="col-md-6"> <input type="text" class="form-control" id="validcode"> </div> <div class="col-md-6"> <img width="350" height="38" src="/get_valid_img/" alt="" id="img"> </div> </div> </div> <input type="button" class="btn btn-primary pull-right login_btn" value="登录"> <span class="error"></span> </form> </div> </div> </div> <script src="/static/js/jquery.js"></script> <script> $(".login_btn").click(function () { $.ajax({ url:"", type:"post", data:{ user:$("#user").val(), pwd:$("#pwd").val(), validcode:$("#validcode").val(), csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val() }, success:function (response) { if(response.user){ // 登录成功 location.href="http://www.luffycity.com" } else{ // 登录失败 $(".error").html(response.err_msg).css("color","red") } } }) }) // 验证码刷新 $("#img").click(function () { this.src+="?" }) </script> </body> </html>
1、当用户访问 http://127.0.0.1:8000/login/ 时,Python自动生成一张图片输入到页面(即:验证码),并将图片上的文字内容保存在 Session中(即:request.session["CheckCode"] = '验证码的文字内容')。
2、用户输入用户名密码,点击登陆时:
- 首先,检查用户输入的 验证码 是否和Session中保存的验证码相同
- 然后,检查用户输入的 用户名 和 密码是否正确
使用checkcode示例:
1、生成验证码图片 <img src='/check_code/'/> session['CheckCode'] = code
2、看图片,输入图片上的内容
3、用户输入的值和session['CheckCode']进行比较
4、用户名和密码的验证
1 views.py 2 3 import io 4 import json 5 from django.shortcuts import HttpResponse, redirect, render 6 from web.forms.account import SendMsgForm, RegisterForm, LoginForm 7 from web import models 8 from backend.utils import check_code as CheckCode 9 from backend.utils.response import BaseResponse 10 def check_code(request): 11 """ 12 获取验证码 13 :param request: 14 :return: 15 """ 16 stream = io.BytesIO() 17 # 创建随机字符 code 18 # 创建一张图片格式的字符串,将随机字符串写到图片上 19 img, code = CheckCode.create_validate_code() 20 img.save(stream, "PNG") 21 # 将字符串形式的验证码放在Session中 22 request.session["CheckCode"] = code 23 return HttpResponse(stream.getvalue()) 24 def login(request): 25 """ 26 用户登陆 27 :param request: 28 :return: 29 """ 30 rep = BaseResponse() 31 form = LoginForm(request.POST) 32 if form.is_valid(): 33 _value_dict = form.clean() 34 if _value_dict['code'].lower() != request.session["CheckCode"].lower(): 35 rep.message = {'code': [{'message': '验证码错误'}]} 36 return HttpResponse(json.dumps(rep.__dict__)) 37 # 验证码正确 38 from django.db.models import Q 39 40 con = Q() 41 q1 = Q() 42 q1.connector = 'AND' 43 q1.children.append(('email', _value_dict['user'])) 44 q1.children.append(('password', _value_dict['pwd'])) 45 46 q2 = Q() 47 q2.connector = 'AND' 48 q2.children.append(('username', _value_dict['user'])) 49 q2.children.append(('password', _value_dict['pwd'])) 50 51 con.add(q1, 'OR') 52 con.add(q2, 'OR') 53 54 obj = models.UserInfo.objects.filter(con).first() 55 if not obj: 56 rep.message = {'user': [{'message': '用户名邮箱或密码错误'}]} 57 return HttpResponse(json.dumps(rep.__dict__)) 58 59 request.session['is_login'] = True 60 request.session['user_info'] = {'nid': obj.nid, 'email': obj.email, 'username': obj.username} 61 rep.status = True 62 else: 63 error_msg = form.errors.as_json() 64 rep.message = json.loads(error_msg) 65 66 return HttpResponse(json.dumps(rep.__dict__)) 67 68 69 70 html 71 72 73 <div id="model_login" class="login left"> 74 <div class="header">登陆</div> 75 <div class="content"> 76 <div style="padding: 0 70px"> 77 <div class="tips"> 78 <span>用户名登陆</span> 79 <span style="padding: 0 5px;">|</span> 80 <span>邮箱登陆</span> 81 </div> 82 <div id="login_error_summary" class="error-msg"> 83 84 </div> 85 <div class="inp"> 86 <input name="user" type="text" placeholder="请输入用户名或邮箱" /> 87 </div> 88 <div class="inp"> 89 <input name="pwd" type="password" placeholder="请输入密码" /> 90 </div> 91 <div class="inp clearfix"> 92 <input name="code" class="check-code" type="text" placeholder="请输入验证码" /> 93 <span> 94 <img class="check-img" src="/check_code/" alt="验证码" onclick="ChangeCode(this);"> 95 </span> 96 97 </div> 98 <div class="extra"> 99 <input type="checkbox" name="autoLogin" checked="checked" /> <span>一个月内自动登录</span> 100 <a class="right" href="javascript:void(0);">忘记密码?</a> 101 </div> 102 <div class="inp"> 103 <div class="submit" onclick="SubmitLogin(this);"> 104 <span>登陆</span> 105 <span class="hide"> 106 <img src="/statics/images/loader.gif" style="height: 16px;width: 16px"> 107 <span>正在登陆</span> 108 </span> 109 </div> 110 </div> 111 </div> 112 <script> 113 function ChangeCode(ths) { 114 ths.src += '?'; 115 } 116 </script> 117 </div> 118 </div> 119 120 /* 121 点击注册按钮 122 */ 123 function SubmitRegister(ths){ 124 $('#register_error_summary').empty(); 125 $('#model_register .inp .error').remove(); 126 127 $(ths).children(':eq(0)').addClass('hide'); 128 $(ths).addClass('not-allow').children(':eq(1)').removeClass('hide'); 129 130 var post_dict = {}; 131 $('#model_register input').each(function(){ 132 post_dict[$(this).attr("name")] = $(this).val(); 133 }); 134 135 $.ajax({ 136 url: '/register/', 137 type: 'POST', 138 data: post_dict, 139 dataType: 'json', 140 success: function(arg){ 141 if(arg.status){ 142 window.location.href = '/index'; 143 }else{ 144 $.each(arg.message, function(k,v){ 145 //<span class="error">s</span> 146 var tag = document.createElement('span'); 147 tag.className = 'error'; 148 tag.innerText = v[0]['message']; 149 $('#model_register input[name="'+ k +'"]').after(tag); 150 }) 151 } 152 } 153 }); 154 155 $(ths).removeClass('not-allow').children(':eq(1)').addClass('hide'); 156 $(ths).children(':eq(0)').removeClass('hide'); 157 }