Django教程第4章 | Web开发实战-三种验证码实现

系列:Django学习教程

验证码的存在是为了防止系统被暴力破解攻击,几乎每个系统都有验证码。下面将介绍三种生成验证码方式。

您可以根据你自己的需要进行学习。

手动生成验证码

安装绘图依赖,利用的是画图模块 PIL 以及随机模块 random 在后台生成一个图片和一串随机数,然后保存在内存中。

pip install pillow

编写跨图工具

code.py

注意需要指定 Monaco.ttf 字体 ,我这里直接放在项目根目录:font_file='Monaco.ttf'

import random
from PIL import Image, ImageDraw, ImageFont, ImageFilterdef check_code(width=120, height=30, char_length=5, font_file='Monaco.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 str(random.randint(0, 9))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__':img, code_str = check_code()print(code_str)

编写视图函数

views.py

LoginForm类:配置登录表单,涵盖用户名、密码和验证码。返回给模板HTML用于渲染页面。

image_code 函数:调用pillow函数,生成图片,设置60秒写入到自己的session中(以便于后续获取验证码再进行校验)

login函数:验证码这块代码主要是校验从前端传过来的验证码是否跟存在session中的验证码一致,如果一直则继续执行下面代码。否则抛出验证码错误异常。

class LoginForm(BootstrapForm):username = forms.CharField(label="用户名",widget=forms.TextInput,required=True)password = forms.CharField(label="密码",widget=forms.PasswordInput(render_value=True),required=True,)code = forms.CharField(label="验证码",widget=forms.TextInput,required=True)def image_code(request):""" 生成图片验证码 """# 调用pillow函数,生成图片img, code_string = check_code()# 写入到自己的session中(以便于后续获取验证码再进行校验)request.session['image_code'] = code_string# 给Session设置60s超时request.session.set_expiry(60)stream = BytesIO()img.save(stream, 'png')return HttpResponse(stream.getvalue())def login(request):if request.method == 'GET':form = LoginForm()return render(request, 'login.html', {'form': form})form = LoginForm(data = request.POST)if form.is_valid():# 验证码的校验user_input_code = form.cleaned_data.pop('code')code = request.session.get('image_code', "")if code.upper() != user_input_code.upper():form.add_error("code", "验证码错误")return render(request, 'login.html', {'form': form})# 查询数据库匹配用户名密码是否正确user_obj = models.UserInfo.objects.filter(**form.cleaned_data).first()print(user_obj)if not user_obj:form.add_error('password', '用户名或密码错误')return render(request, 'login.html', {'form': form})request.session['info'] = {'id': user_obj.id, 'username': user_obj.username}# 设置 session 过期时间为30分钟request.session.set_expiry(60 * 30)return redirect('/user/list/')return render(request, 'login.html', {'form': form})

login.html

{{ form.code }}:验证码。
{{ form.code.errors.0 }}:验证码输出错误时返回错误提示。

img 标签设置 onclick事件,当用户单击验证码图片生成一个新的验证码。
相当于向服务器发送请求:http://localhost:8000/image/code/?temp=随机数

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>用户管理系统</title><link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.min.css' %}"><style>.account {width: 400px;border: 1px solid #dddddd;border-radius: 5px;box-shadow: 5px 5px 20px #aaa;margin-left: auto;margin-right: auto;margin-top: 100px;padding: 20px 40px;}.account h2 {margin-top: 10px;text-align: center;}</style>
</head>
<body>
<div class="account"><h2>用户登录</h2><form method="post" novalidate>{% csrf_token %}<div class="form-group"><label>用户名</label>{{ form.username }}<span style="color: red;">{{ form.username.errors.0 }}</span></div><div class="form-group"><label>密码</label>{{ form.password }}<span style="color: red;">{{ form.password.errors.0 }}</span></div><div class="form-group"><label for="id_code">图片验证码</label><div class="row"><div class="col-xs-7">{{ form.code }}<span style="color: red;">{{ form.code.errors.0 }}</span></div><div class="col-xs-5"><img id="image_code" src="/image/code/" onclick="refreshImg(this)" style="width: 125px;" /></div></div></div><input type="submit" value="登 录" class="btn btn-primary"></form>
</div>
</body>
<script>function refreshImg(ths) {ths.src = '/image/code/?temp=' + Math.random();}
</script>
</html>

配置路由

path('login/', views.login),
path('image/code/', views.image_code),

4380bde6a2c44d15ba7cd469c8a4b05d.png

总结

  • 画图程序 check_code.py 保存在项目任意位置即可,只需在视图函数中导入即可。
  • Monaco.ttf 字体不可或缺,放置在静态文件中即可,但是需要修改 check_code.py 中的字体引入路径。
  • 验证用户输入的验证码是否正确,只需从 session 中取出生成的验证码与其比较即可。
  • 验证码刷新,只需让其再发送一次 get 请求即可。

自动生成验证码

1.安装 django-simple-captcha模块

pip install django-simple-captcha

2.注册到django容器

在 settings.py添加以下内容

INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','ums.apps.UmsConfig','captcha',
]

更新数据库表,

3.添加路由

在 urls.py 中添加 captcha 对应的路由

from django.contrib import admin
from django.urls import path, includeurlpatterns = [path('admin/', admin.site.urls),path('captcha', include('captcha.urls')),        # 验证码
]

4.修改Form表单

Django 中通常都是由 Form 生成表单,而验证码一般也伴随注册登录表单,因此需要在 forms.py 中添加验证码的字段。

from django import forms
from captcha.fields import CaptchaField     # 一定要导入这行class UserForm(forms.Form):username = forms.CharField(label='用户名',                # 在表单里表现为 label 标签max_length=128,widget=forms.TextInput(attrs={'class': 'form-control'})   # 添加 css 属性)captcha = CaptchaField(label='验证码',required=True,error_messages={'required': '验证码不能为空'})

5.编写视图函数

from django.shortcuts import render
from app.forms import UserFormdef index(request):register_form = UserForm(request.POST)if register_form.is_valid():passregister_form = UserForm()return render(request, 'index.html', {'register_form': register_form})

6.编写模板 

<html><head></head><body><form action='#' method='post'>{{ register_form.captcha.label_tag }}{{ register_form.captcha }} {{ </form></body>
</html>

总结

使用django-simple-captcha第三方库会生成验证码并存储到自带的captcha表中。

滑动验证码

官方下载源码包,并安装 geetest 模块​​​​​​

geetest-Getting started

gt3-python-sdk 文件。

pip install geetest
pip install requests    # 有可能还需要 requests 模块<!-- 引入封装了failback的接口--initGeetest -->
<script src="http://static.geetest.com/static/tools/gt.js"></script>

编写模板template

login.html

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登录</title><link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.css' %}"><style>.login-col {margin-top: 100px;}</style>
</head>
<body>
<div class="container"><div class="row"><div class="well col-md-6 col-md-offset-3 login-col"><h3 class="text-center">登录</h3><form>{% csrf_token %}<div class="form-group"><label for="username">用户名:</label><input type="text" class="form-control" id="username" placeholder="用户名" name="username"></div><div class="form-group"><label for="password">密码:</label><input type="password" class="form-control" id="password" placeholder="密码" name="password"></div><!--极验科技滑动验证码--><div class="form-group"><!-- 放置极验的滑动验证码 --><div id="popup-captcha"></div></div><!--记住我--><div class="checkbox"><label><input type="checkbox"> 记住我</label></div><!--登录按钮--><button type="button" class="btn btn-primary btn-block" id="login-button">提交</button><!--错误信息--><span class="login-error"></span></form></div></div>
</div>
</body>
</html>

JS 代码主要分为两部分,

第一部分是获取表单的 value 值,向后台发送 Ajax 请求,以验证用户名及密码是否正确,若有错误将错误信息显示出来。

第二部分向后台获取验证码所需相关参数。 

<script src="{% static 'js/jquery-3.3.1.js' %}"></script>
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.js' %}"></script>
<!-- 引入封装了failback的接口--initGeetest -->
<script src="http://static.geetest.com/static/tools/gt.js"></script><script>var handlerPopup = function (captchaObj) {// 成功的回调captchaObj.onSuccess(function () {var validate = captchaObj.getValidate();var username = $('#username').val();var password = $('#password').val();console.log(username, password);$.ajax({url: "/accounts/login2/", // 进行二次验证type: "post",dataType: 'json',data: {username: username,password: password,csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(),geetest_challenge: validate.geetest_challenge,geetest_validate: validate.geetest_validate,geetest_seccode: validate.geetest_seccode},success: function (data) {console.log(data);if (data.status) {// 有错误,在页面上显示$('.login-error').text(data.msg);} else {// 登录成功location.href = data.msg;}}});});// 当点击登录按钮时,弹出滑动验证码窗口$("#login-button").click(function () {captchaObj.show();});// 将验证码加到id为captcha的元素里captchaObj.appendTo("#popup-captcha");// 更多接口参考:http://www.geetest.com/install/sections/idx-client-sdk.html};$('#username, #password').focus(function () {// 将之前的错误清空$('.login-error').text('');});// 验证开始需要向网站主后台获取id,challenge,success(是否启用failback)$.ajax({url: "/accounts/pc-geetest/register?t=" + (new Date()).getTime(), // 加随机数防止缓存type: "get",dataType: "json",success: function (data) {// 使用initGeetest接口// 参数1:配置参数// 参数2:回调,回调的第一个参数验证码对象,之后可以使用它做appendTo之类的事件initGeetest({gt: data.gt,challenge: data.challenge,product: "popup", // 产品形式,包括:float,embed,popup。注意只对PC版验证码有效offline: !data.success // 表示用户后台检测极验服务器是否宕机,一般不需要关注// 更多配置参数请参见:http://www.geetest.com/install/sections/idx-client-sdk.html#config

视图函数 views.py

from django.shortcuts import render, redirect, HttpResponse
from django.http import JsonResponse
from geetest import GeetestLibdef login2(request):if request.method == 'POST':ret = {'status': False, 'msg': None}username = request.POST.get('username')password = request.POST.get('password')print(username, password)# 获取极验,滑动验证码相关参数gt = GeetestLib(pc_geetest_id, pc_geetest_key)challenge = request.POST.get(gt.FN_CHALLENGE, '')validate = request.POST.get(gt.FN_VALIDATE, '')seccode = request.POST.get(gt.FN_SECCODE, '')status = request.session[gt.GT_STATUS_SESSION_KEY]user_id = request.session["user_id"]print(gt, challenge, validate, seccode, status)if status:result = gt.success_validate(challenge, validate, seccode, user_id)else:result = gt.failback_validate(challenge, validate, seccode)if result:# 验证码正确# 利用auth模块做用户名和密码的校验user_obj = auth.authenticate(username=username, password=password)if user_obj:# 用户名密码正确# 给用户做登录auth.login(request, user_obj)ret["msg"] = "/accounts/home/"# return redirect('accounts:home')else:# 用户名密码错误ret["status"] = Trueret["msg"] = "用户名或密码错误!"else:ret["status"] = Trueret["msg"] = "验证码错误"return JsonResponse(ret)return render(request, "accounts/login2.html")# 请在官网申请ID使用,示例ID不可使用
pc_geetest_id = "b46d1900d0a894591916ea94ea91bd2c"
pc_geetest_key = "36fc3fe98530eea08dfc6ce76e3d24c4"# 处理极验 获取验证码的视图
def get_geetest(request):user_id = 'test'gt = GeetestLib(pc_geetest_id, pc_geetest_key)status = gt.pre_process(user_id)request.session[gt.GT_STATUS_SESSION_KEY] = statusrequest.session["user_id"] = user_idresponse_str = gt.get_response_str()return HttpResponse(response_str)

配置路由

from django.urls import path
from accounts import viewsapp_name = 'accounts'
urlpatterns = [path('home/', views.home, name='home'),# 极验滑动验证码 获取验证码的urlpath('pc-geetest/register/', views.get_geetest, name='get_geetest'),path('login2/', views.login2, name='login2'),
]

0ef2e2dae3264248a83fa1b5b2b712dd.png

总结

  • 画图程序 check_code.py 保存在项目任意位置即可,只需在视图函数中导入即可。
  • Monaco.ttf 字体不可或缺,放置在静态文件中即可,但是需要修改 check_code.py 中的字体引入路径。
  • 验证用户输入的验证码是否正确,只需从 session 中取出生成的验证码与其比较即可。
  • 验证码刷新,只需让其再发送一次 get 请求即可。

需要源代码评论区可以给我留言!

如果本文对你有帮助,记得点赞关注,你的支持是我最大的动力!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/624498.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙开发-UI-布局-线性布局

鸿蒙开发-序言 鸿蒙开发-工具 鸿蒙开发-初体验 鸿蒙开发-运行机制 鸿蒙开发-运行机制-Stage模型 鸿蒙开发-UI 鸿蒙开发-UI-组件 鸿蒙开发-UI-组件-状态管理 鸿蒙开发-UI-应用-状态管理 鸿蒙开发-UI-渲染控制 鸿蒙开发-UI-布局 文章目录 前言 一、基本概念 二、布局子元素 1.子元…

User-Agent(用户代理)是什么?

User-Agent&#xff08;用户代理&#xff09;是什么&#xff1f; User-Agent 即用户代理&#xff0c;简称“UA”&#xff0c;它是一个特殊字符串头。网站服务器通过识别 “UA”来确定用户所使用的操作系统版本、CPU 类型、浏览器版本等信息。而网站服务器则通过判断 UA 来给客…

Hotspot源码解析-第十九章-ClassLoaderData、符号表、字符串表的初始化

第十九章-ClassLoaderData初始化 讲解本章先从一张图开始 众所周知&#xff0c;Java类的相关信息都是存储在元空间中的&#xff0c;但是是怎么存储的&#xff0c;相信很多读者是不清楚的&#xff0c;这里就不得不涉及到ClassLoaderDataGraph、classLoader、classLoaderData&…

MIT 6s081 lab 5: xv6 lazy page allocation

Page faults Basic 通过page fault可以实现一系列的虚拟内存功能&#xff1a; lazy allocationcopy-on-write forkdemand pagingmemory mapped files 虚拟内存的两个主要的优点&#xff1a; 1、隔离性&#xff1a;每个应用程序拥有自己的地址空间&#xff0c;因此不可能修…

【Dart】=> [06] Dart初体验-类Class-构造函数-继承-mixin-异步编程-链式调用-泛型-异常

目录 能够定义并使用Dart的类类的定义构造函数私有属性和方法继承mixin异步编程FutureFuture链式调用async - awaitdynamic类型泛型异常 能够定义并使用Dart的类 Dart是一门面向对象的编程语言&#xff0c;所有的对象都是类的实例 通过类我们可以对数据和方法进行封装复用 学习…

(2023版)斯坦福CS231n学习笔记:DL与CV教程 (1) | 引言与知识基础

前言 &#x1f4da; 笔记专栏&#xff1a;斯坦福CS231N&#xff1a;面向视觉识别的卷积神经网络&#xff08;23&#xff09;&#x1f517; 课程链接&#xff1a;https://www.bilibili.com/video/BV1xV411R7i5&#x1f4bb; CS231n: 深度学习计算机视觉&#xff08;2017&#xf…

NLP论文阅读记录 - 2022 | WOS 用于摘要法律文本的有效深度学习方法

文章目录 前言0、论文摘要一、Introduction1.1目标问题 二.相关工作三.本文方法四 实验效果4.1数据集4.2 对比模型4.3实施细节4.4评估指标4.5 实验结果4.6 细粒度分析 五 总结 前言 Effective deep learning approaches for summarization of legal texts&#xff08;22&#x…

Linux -- Nginx服务基础

4.1Nginx服务基础 Nginx(发音为[engine x])专为性能优化而开发&#xff0c;其最知名的优点是它的稳定性和低系统资源消 耗&#xff0c;以及对HTTP并发连接的高处理能力&#xff08;单台物理服务器可支持30000~50000个并发请求&#xff09;&#xff0c;正因 为如此&#xff0c;…

vscode中关于python的一些常用配置

文章目录 python cv2 提示配置第一步 配置提示信息第二部 重启vs 可能还不行&#xff0c;那就重新安装以下opencv-python 配置pytest还是如上&#xff0c;将下入的位置打开编写测试用例 配置跨文件import在工作目录中新建一个.env文件输入内容如下打开.vscode中的setting.json …

目标识别跟踪模块Tofu3

Tofu系列提供了适应不同目标、不同速率的识别跟踪模块产品系列&#xff0c;主要包括Tofu3&#xff0c;4&#xff0c;5&#xff0c;S和其他零配件&#xff0c;可以适配BT.656,Cameralink&#xff0c;网络等不同接口和协议的热红外、可见光视频。 Tofu3 是多波段视频物体识别跟踪…

GL Logger和CANFDLog-OTL-128两款记录仪都是如何实现高效的报文录制的?

GL Logger是Vector推出的记录CAN/CAN FD、LIN、FlexRay和MOST数据通信的工具。以GL2400为例带着大家一步步地实现路试过程中通过整车OBD口进行CAN/CANFD报文的录制。 Step1 设备配置 设备配置即设备录制方式、录制内容、设备休眠唤醒策略等。 ▷ 打开Vector Logger Configurat…

UML-用例图

提示&#xff1a;用例图是软件建模的开始&#xff0c;软件建模中的其他图形都将以用例图为依据。用例图列举了系统所需要实现的所有功能&#xff0c;除了用于软件开发的需求分析阶段&#xff0c;也可用于软件的系统测试阶段。 UML-用例图 一、用例图的基础知识1.用例图的构成元…

使用numpy处理图片——滤镜

大纲 3维数组切分打平重组法深度切分法 3维数组堆叠 我们在用手机拍照片时&#xff0c;往往会对照片进行滤镜处理&#xff0c;从而让照片更加美观。本文我们将实现几种滤镜效果——去除所有像素中的某一种原色&#xff0c;形成只有红绿、红蓝和绿蓝原色的照片。 为了突出色彩丰…

定制服务器有什么优势优点?

定制服务器是指在根据用户的需求和业务特点&#xff0c;专门设计和制造的服务器。与标准服务器相比&#xff0c;定制服务器具有以下优势和优点&#xff1a; 更好的性能&#xff1a;定制服务器可以针对特定应用进行优化&#xff0c;从而提高服务器的性能。由于定制服务器不需要…

Win和Mac系统重置系统方法

注意&#xff1a;重置系统前&#xff0c;请备份好系统盘资料到其他盘符&#xff01;重置系统将会删除应用和系统设置&#xff0c;甚至用户文件&#xff0c;还原为出厂设置模式。 Windows重置系统操作方法。&#xff08;目前支持WIN8&#xff0c;WIN10&#xff0c;WIN11&#x…

Linux系统使用docker部署Geoserver(简单粗暴,复制即用)

1、拉取镜像 docker pull kartoza/geoserver:2.20.32、创建数据挂载目录 # 统一管理Docker容器的数据文件,geoserver mkdir -p /mydata/geoserver# 创建geoserver的挂载数据目录 mkdir -p /mydata/geoserver/data_dir# 创建geoserver的挂载数据目录&#xff0c;存放shp数据 m…

【数据库原理】(24)数据库安全性策略

数据库安全性是数据库管理系统&#xff08;DBMS&#xff09;中一个至关重要的方面。它指的是保护数据库免受非授权访问和恶意操作&#xff0c;包括数据泄露、修改、破坏等。 多层安全模型 在典型的计算机系统安全模型中&#xff0c;安全措施被设置在不同层级&#xff1a; 应用…

Unity ComputeShader 使用GPU快速计算复杂问题

Unity ComputeShader 使用GPU快速计算复杂问题 前言项目创建ComputeShader编写CompturShader创建Unity代码场景布置运行场景 参考 前言 遇到一个问题&#xff0c;需要大量的计算&#xff0c;在Unity中直接写会长时间的阻塞主线程&#xff0c;正好使用ComputeShader让GPU来帮我…

海格里斯HEGERLS仓储货架生产厂家|载荷1.5T运行速度1.7~2m/s的智能四向穿梭车系统

四向穿梭车立体库是近年来出现的一种智能型密集系统&#xff0c;通过使用四向穿梭车在货架的水平和纵向轨道上运行来搬运货物&#xff0c;一台四向穿梭车就能完成货物的搬运工作&#xff0c;大大提高了工作效率。同时配合提升机、自动化仓库管理系统(WMS)和仓库调度系统(WCS)&a…

使用WAF防御网络上的隐蔽威胁之SSRF攻击

服务器端请求伪造&#xff08;SSRF&#xff09;攻击是一种常见的网络安全威胁&#xff0c;它允许攻击者诱使服务器执行恶意请求。与跨站请求伪造&#xff08;CSRF&#xff09;相比&#xff0c;SSRF攻击针对的是服务器而不是用户。了解SSRF攻击的工作原理、如何防御它&#xff0…