用python实现一个简单的验证码
作者:极客运维圈 发布时间:2023-05-23 12:07:58
目录
简单的验证码
简单的登录页面
我们经常在登录一个网站,或者注册的时候需要输入一个验证码,有时候觉得很烦,因为有些验证码不仅复杂还看不清,许多用户就会因为这些而懒得再登录或者注册之类的。
既然验证码会造成流失用户的风险,为什么大家都还要使用验证码呢?
这是验证码在一定程度上起到保护网站安全的作用,比如防止大规模恶意注册(比如手机验证码形式,一机一户),再比如反爬虫(至少不会轻易让你爬取数据)等,你看用户基数最大的12306,就会有各种验证码。
既然验证码这么重要,它的原理是什么?是怎么实现的?
它的原理其实很简单,就是在服务器端生成验证码,发送给客户端,并以图像格式显示。客户端提交所显示的验证码,服务端接收并进行比较,若比对失败则不能实现登录或注册,反之成功后跳转相应界面。
我们知道了其原理,实现起来就很简单了,现在网络上也有各种各样已经做好的验证码,我们完全可以拿来即用。但是为了更好的理解其原理,我们来手撸一个简单的验证码,以下是在Django中实现。
简单的验证码
(1)、我们在urls.py中定义一条路由,如下:
url(r'getcode', views.get_code, name="get_code"),
(2)、我们定义一个视图函数get_code(),如下:
from io import BytesIO
from PIL import Image, ImageDraw, ImageFont
from django.conf import settings
from django.shortcuts import render, HttpResponse, redirect
def get_code(request):
"""
手撸一个验证码
"""
# 定义图像颜色模型
mode = "RGB"
# 定义图像尺寸
size = (200, 100)
# 定义背景色
bg_color = (255, 0, 0)
# 创建图像
image = Image.new(mode=mode, size=size, color=bg_color)
# 创建画布
image_draw = ImageDraw.Draw(image, mode=mode)
# 创建字体,第一个参数是字体,第二个参数是字体大小
image_font = ImageFont.truetype(settings.FONT_PATH, 100)
# 创建一个验证码
verify_code = "Joke"
# 生成验证码
fill_color = (255,255,255)
for i in range(4):
image_draw.text(xy=(50 * i, 0), text=verify_code[i], font=image_font, fill=fill_color)
# 保存图像
fp = BytesIO()
image.save(fp, "png")
return HttpResponse(fp.getvalue(), content_type="image/png")
其中settings.FONT_PATH是我预先定义好的字段,如下
STATICFILES_DIRS = [ os.path.join(BASE_DIR, "statics"),]
FONT_PATH = os.path.join(os.path.join(STATICFILES_DIRS[0], "fonts"),"constan.ttf")
然后我们我们启动服务python manager.py runserver,在浏览器上就可以看到验证码生成了
能是实现了,但是我们现在是自定义了一个验证码字段,我们是需要随机生成验证码,而且字体颜色,背景颜色这些也不要定死了,然后我们再生成一些干扰点,我们对代码进行如下重构:
def get_code(request):
"""
手撸一个验证码
"""
# 定义图像颜色模型
mode = "RGB"
# 定义图像尺寸
size = (200, 100)
# 定义背景色
bg_color = (get_color(), get_color(), get_color())
# 创建图像
image = Image.new(mode=mode, size=size, color=bg_color)
# 创建画布
image_draw = ImageDraw.Draw(image, mode=mode)
# 创建字体,第一个参数是字体,第二个参数是字体大小
image_font = ImageFont.truetype(settings.FONT_PATH, 100)
# 创建一个验证码
# verify_code = "Joke"
verify_code = get_verify_code()
# 生成验证码
# fill_color = (255,255,255)
for i in range(4):
fill_color = (get_color(),get_color(),get_color())
image_draw.text(xy=(50 * i, 0), text=verify_code[i], font=image_font, fill=fill_color)
# 加入干扰点
for i in range(10000):
fill_color = (get_color(),get_color(),get_color())
xy = (random.randrange(200), random.randrange(100))
image_draw.point(xy=xy,fill=fill_color)
# 保存图像
fp = BytesIO()
image.save(fp, "png")
return HttpResponse(fp.getvalue(), content_type="image/png")
def get_color():
"""随机获取颜色"""
return random.randrange(256)
def get_verify_code():
"""随机获取验证码"""
verify_code = ''.join(random.choice(string.ascii_uppercase + string.digits + string.ascii_lowercase) for x in range(4))
return verify_code
然后我们重启应用,刷新页面如下
是不是有点神似了?下面我们创建一个简单的login页面,来实际应用一下验证码。
简单的登录页面
(1)、创建一个路由
url(r'login',views.login, name="login"),
(2)、创建一个Login的视图函数
def login(request):
"""登录页面"""
if request.method == "POST":
pass
return render(request, "login.html")
(3)、创建一个login.html的template
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<form action="{% url 'app01:login' %}" method="post">
{% csrf_token %}
<span>用户名:</span><input type="text" name="username">
<br>
<span>验证码:</span><input type="text" name="verify_code">
<br>
<img src="{% url 'app01:get_code' %}" alt="">
<br>
<button>登录</button>
</form>
</body>
</html>
然后重启服务,浏览器访问如下
现在我们只是简单的搭建起了流程,我们需要的功能还没有实现,我们需要的功能有:
1、验证码校验
2、点击图片自动刷新验证码
3、忽略大小写
我们现在对项目进行重构,如下:
(1)、我们在get_code视图函数添加一行代码,如下
# 创建一个验证码
# verify_code = "Joke"
verify_code = get_verify_code()
# 加入session
request.session['verify_code'] = verify_code
......
(2)、修改login视图函数,如下
def login(request):
"""登录页面"""
if request.method == "POST":
storage_code = request.session.get("verify_code")
submit_code = request.POST.get("verify_code")
if storage_code.lower() == submit_code.lower():
return HttpResponse("登录成功")
return render(request, "login.html")
(3)、修改login.html代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<form action="{% url 'app01:login' %}" method="post">
{% csrf_token %}
<span>用户名:</span><input type="text" name="username">
<br>
<span>验证码:</span><input type="text" name="verify_code">
<br>
<img src="{% url 'app01:get_code' %}" alt="" name="verify_image">
<br>
<button>登录</button>
</form>
<script src="https://cdn.bootcss.com/jquery/3.2.0/jquery.js"></script>
<script>
$(function () {
$("img").on("click", function () {
console.log("来了啊")
$(this).attr("src","{% url 'app01:get_code' %}"+"?id="+Math.random())
})
})
</script>
</body>
</html>
然后就可以愉快的玩耍了,是不是很简单呢?
来源:https://www.cnblogs.com/coolops/p/13577577.html


猜你喜欢
- laravel入门简介作为PHP最常用的框架之一,Laravel的框架目录布置得尤其清晰,适用于各种类型的项目开发。今天来记录下larave
- PDOStatement::fetchObjectPDOStatement::fetchObject — 获取下一行并作为一个对象返回。(P
- SQL Server数据库备份有两种方式,一种是使用BACKUP DATABASE将数据库文件备份出去,另外一种就是直接拷贝数据库文件mdf
- 简介细胞自动机(又称元胞自动机),名字虽然很深奥,但是它的行为却是非常美妙的。所有这些怎样实现的呢?我们可以把计算机中的宇宙想象成是一堆方格
- 目录1.Python语法错误2.Python运行时错误前言:开发人员在编写程序时,难免会遇到错误,有的是编写人员疏忽造成的语法错误,有的是程
- python爬虫主要用两个库:Urllib和BeautifulSoup4。一个用来爬取网页,一个用来解析网页。Urllib是Python内置
- 有时候会需要通过从保存下来的ckpt文件来观察其保存下来的训练完成的变量值。ckpt文件名列表:(一般是三个文件)xxxxx.ckpt.da
- 我们大家都知道MySQL数据库在安装完之后,默认的MySQL数据库,其最大连接数为100,一般流量稍微大一点的论坛或网站这个连接数是远远不够
- 本文实例讲述了Python分支语句与循环语句应用。分享给大家供大家参考,具体如下:一、分支语句1、if else语句语法:if 条件判断:
- 在本教程中,我们将学习使用OpenCV跟踪对象。OpenCV 3.0开始引入跟踪API。我们将学习如何和何时使用OpenCV 4.2中可用的
- 首先,你需要去有道翻译API官网去申请key:http://fanyi.youdao.com/openapi?path=data-mode得
- 本文只有代码,介绍了有关GUI界面的学生信息管理系统的实现。已经过调试没有很大问题。如有错误,还请批评指正。1.导入tkinter模块imp
- Dataset类是TensorFlow非常流行的存储数据的格式。常用来作为输入输出。data模块主要的用途就是通过这种方法创建Dataset
- 本文实例讲述了Python3.5变量、数据结构、条件和循环语句、break与continue语句。分享给大家供大家参考,具体如下:1、变量:
- 本文实例讲述了Python基于pyCUDA实现GPU加速并行计算功能。分享给大家供大家参考,具体如下:Nvidia的CUDA 架构为我们提供
- 一、MySQL中如何表示当前时间?其实,表达方式还是蛮多的,汇总如下:CURRENT_TIMESTAMPCURRENT_TIMESTAMP(
- 大致功能:$() 取得所有元素$("div") 取得所有DIV$("#a1") 取得ID为a1的元素
- 本文实例讲述了Python捕捉和模拟鼠标事件的方法。分享给大家供大家参考。具体分析如下:这个假期玩了不少galgame,不过有些很老的游戏没
- 长期以来一直以为iframe跟div一样都是块级元素,直到今天在一个群中看到一位朋友问到iframe怎么居中的时候,测试了下发现原来我一直对
- 1、 引言小 * 丝:鱼哥,新年快乐!小鱼:无事不登三宝殿,有啥事,你直说吧…小 * 丝:别说的这么直接,这大过年的&