图片和短信验证码(头条项目-06)
1 图形验证码接口设计
将后端⽣成的图⽚验证码存储在redis数据库2号库。
结构:
- {'img_uuid':'0594'}
1.1 创建验证码⼦应⽤
$ cd apps
$ python ../../manage.py startapp verifications
# 注册新应⽤
INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','userapp','newsapp','verifications',
]
1.2 图形验证码接⼝设计
1.2.1 请求⽅式
选项 | ⽅案 |
请求⽅法 | GET |
请求地址 1 | /imgcodes/(?P[\w-]+)/ |
1.2.2 请求参数:路径参数
参数名 | 类型 | 是否必传 | 说明 |
uuid | string | 是 | 唯⼀编号 |
1.2.3 响应结果 图⽚验证码格式:image/png
1.3 图形验证码接⼝定义
1.3.1 图形验证码视图
# views.py视图⽂件
class ImageCode(View):def get(self, request, uuid):pass
1.3.2 配置路由
# 项⽬根路由
re_path('^', include(('verifications.urls', 'verifications',),namespace='verify')),
# ⼦路由
re_path('^image_code/(?P<uuid>[\w-]+)/$', views.ImageCode.as_view())
2 图片验证码后端逻辑
2.1 配置Redis数据库
# 配置redis数据库专⻔存储验证码
"verify_code": { # 验证码"BACKEND": "django_redis.cache.RedisCache","LOCATION": "redis://192.168.1.6:6379/2","OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient",}
}
2.2 安装模块
pip install pillow
pip install captcha
2.3 图⽚验证码视图
# constants.py⽂件内容
# 图⽚验证码有效期,单位:秒
IMAGE_CODE_REDIS_EXPIRES = 300# views.py视图⽂件
from captcha.image import ImageCaptcha
from django_redis import get_redis_connection
from newsdemo.apps.verifications import constantsclass ImageCode(View):def get(self, request, uuid):# 随机⽣成四位数字seeds = string.digitsrandom_str = random.choices(seeds, k=4)imgcode = "".join(random_str)# ⽣成图⽚验证码img = ImageCaptcha().generate(chars=imgcode)# 保存图⽚验证码到redisredis_conn = get_redis_connection('verify_code')redis_conn.setex('img_%s' % uuid, constants.IMAGE_CODE_REDIS_EXPIRES, imgcode)return http.HttpResponse(img, content_type='image/png')
3 图片验证码前端逻辑
3.1 Vue实现图形验证码展示
3.1.1 register.js
mounted(){// ⽣成图形验证码this.generate_img_code();},
methods:{generate_img_code:function () {// ⽣成UUID generateUUID() : 封装在common.js⽂件中,需要提前引⼊this.uuid = generateUUID();// 拼接图形验证码请求地址this.img_url = "/imgcodes/" + this.uuid + "/";},
...
}
3.1.2 register.html
<p class="form-row form-row-wide"><input style="width: 250px;" placeholder="图⽚验证码"type="text" class="input-text"><img style="height: 40px;float: right;" :src="img_url"@click="generate_img_code"><span class="error-tip">图⽚验证码有误</span>
</p>
3.1.3 图形验证码展示和存储效果
3.2 Vue实现图形验证码校验
3.2.1 register.html
<p class="form-row form-row-wide"><input style="width: 250px;" placeholder="图⽚验证码" v-model='imgcode' @blur="check_imgcode" name="imgcode"type="text" class="input-text"><img style="height: 40px;float: right;" :src="img_url"@click="generate_img_code"><span class="error-tip" v-show="error_imgcode">${error_imgcode_msg}</span>
</p>
3.2.2 register.js
// 校验图⽚验证码
check_imgcode:function () {if (!this.imgcode) {this.error_imgcode_msg = '请填写图⽚验证码';this.error_imgcode = true;} else {this.error_imgcode = false;}
}
3.2.3 校验效果
4 短信验证码接口设计
4.1 短信验证码接⼝设计
4.1.1 请求⽅式
选项 | ⽅案 |
请求⽅法 | GET |
请求地址 1 | /sms_codes/(?P1[35789]\d{9})/ |
4.1.2 请求参数:路径参数和查询字符串
参数名 | 类型 | 是否必传 | 说明 |
phone | string | 是 | ⼿机号 |
imgcode | string | 是 | 图⽚验证码 |
uuid | string | 是 | 唯⼀编号 |
4.1.3 响应结果:JSON
响应结果 | 响应内容 |
code | 状态码 |
errmsg | 错误信息 |
4.2 短信验证码接⼝定义
class SMSCode(View):"""短信验证码"""def get(self, reqeust, phone):""":param reqeust: 请求对象:param phone: ⼿机号:return: JSON"""pass
4.3 知识要点
- 保存短信验证码是为注册做准备的。
- 为了避免⽤户使⽤图形验证码恶意测试,后端提取了图形验证码后,⽴即删除图形验证码。
- Django不具备发送短信的功能,所以我们借助 第三⽅的互亿⽆线短信平台 来帮助我们发送短信验证码。
5 互亿无线短信平台
5.1 平台介绍
互亿⽆线官⽹ https://www.ihuyi.com/
⽬前注册可免费使⽤50条短信验证码
5.2 平台管理中⼼
5.3 接⼊⽂档
跳转地址:短信验证码接入指南_短信平台帮助_互亿无线 (ihuyi.com)
5.4 配置参数
在dev.py配置⽂件中添加参数
# 互亿⽆线短信验证码参数
# APIID
APIID = "C74**64"
# APIKEY
APIKEY = "62de***8932d50c2"
5.5 下载Python3.8⽀持的SDK
# utils/huyi_sms/sms3.py
# !/usr/local/bin/python
# -*- coding:utf-8 -*-
from urllib.request import urlopen
from urllib.parse import urlencode
from django.conf import settings
import jsondef send_sms_code(smscode, phone):# APIID(⽤户中⼼【验证码通知短信】-【产品纵览】查看)account = settings.APIID# APIKEY(⽤户中⼼【验证码通知短信】-【产品纵览】查看)password = settings.APIKEYtext = "您的验证码是:%s。请不要把验证码泄露给其他⼈。" % smscodedata = {'account': account, 'password': password, 'content': text,'mobile': phone, 'format': 'json'}req = urlopen(url='https://106.ihuyi.com/webservice/sms.php?''method=Submit',data=urlencode(data).encode())content = req.read().decode()print(content)# code等于2代表提交成功,否则提交失败# smsid等于0代表提交失败,否则显示⻓度20流⽔号# b'{"code":2,"msg":"\xe6\x8f\x90\xe4\xba\xa4\xe6\x88\x90\xe5\x8a\x9f",# "smsid":"16063783563405105174"}'return json.loads(content)
6 短信验证码后端逻辑
6.1 短信验证码后端逻辑实现
class SMScodeView(View):def get(self, request, phone):"""匹配并删除图形验证码发送短信验证码:param request::param phone::return:"""# 1. 获取请求参数(路径参数+查询参数)imgcode_client = request.GET.get('imgcode', '')uuid = request.GET.get('uuid', '')# 2. 校验参数if not all([phone, imgcode_client, uuid]):return JsonResponse({'code': '4001', 'errormsg': '缺少必须传递的参数'})# 3. 校验图⽚验证码(⽤户输⼊验证码和⽣成验证码)redis_conn = django_redis.get_redis_connection('verify_code')imgcode_server = redis_conn.get('img_%s' % uuid)print(uuid)print(imgcode_server)# 3.1 图⽚验证码是否过期if imgcode_server is None:return JsonResponse({'code': '4002', 'errormsg': '图⽚验证码已经过期'})# 3.2 匹配图⽚验证码if imgcode_client.lower() != imgcode_server.decode('utf-8').lower():return JsonResponse({'code': '4003', 'errormsg': '图⽚验证码不匹配'})try:# 删除redis中的图⽚验证码redis_conn.delete('img_%s' % uuid)except Exception as e:logger.error(e)# 4. ⽣成短信验证码(6位)seed = string.digitsr = random.choices(seed, k=6)smscode_str = "".join(r)# 5. 保存短信验证码(redis数据库2号库存储)redis_conn.setex('sms_%s' % uuid, 60, smscode_str)# 6. 发送短信验证码ret = send_sms_code(smscode_str, phone)if ret.code == 2:return JsonResponse({'code': 200, 'errormsg': 'OK'})# 7. 返回响应结果return JsonResponse({'code': 5001, 'errormsg': '发送短信验证码错误'})
7 短信验证码前端逻辑
7.1 Vue绑定短信验证码
7.1.1 register.html
<p class="form-row form-row-wide"><input style="width: 250px;" placeholder="短信验证码" v-model='smscode'@blur="check_smscode" name="msgcode"type="text" class="input-text" id="reg_mescode"><span class="error-tip" v-show="error_code">${error_msgcode_msg}</span><a href="javascript:;" style="position: relative;left:150px;"@click="send_code()">${smscode_btn} </a>
</p>
7.1.2 register.js
check_smscode:function () {//获取验证码⻓度let reg = /^\d{6}$/;//校验规则if (!reg.test(this.smscode)) {this.error_smscode_msg = '请填写短信验证码';this.error_smscode = true;} else {this.error_smscode = false;}
}
7.2 axios请求短信验证码
7.2.1 发送短信验证码事件处理
send_smscode:function () {//发送短信验证码//1.判断短信验证码是否正在发送if (this.send_flag) {return;}//2.修改发送状态this.send_flag = true;//3.校验⽤户输⼊的⼿机号和图⽚验证码this.check_phone();this.check_imgcode();if (this.error_phone || this.error_imgcode) {this.send_flag = false;return;}//4.发送短信验证码var url = '/smscodes/' + this.phone + '/?imgcode=' +this.imgcode + '&uuid=' + this.uuid;axios.get(url, {responseType: 'json'}).then(response => {console.log(response.data.code);console.log(typeof (response.data.code));if (response.data.code == '200') {let num = 60;var i = setInterval(() => {if (num == 1) {clearInterval(i);this.smscode_btn = '获取短信验证码';this.send_flag = false;} else {num -= 1;this.smscode_btn = '倒计时:' + num + '秒';}}, 1000, 60)} else {if (response.data.data == '4001' || response.data.data == '4002'|| response.data.data == '4003' || response.data.data == '5001') {this.error_smscode_msg =response.data.errormsg;this.error_smscode = true;}//重新⽣成图⽚验证码this.generate_imgcode();//重置发送状态this.send_flag = false;}}).catch(error => {console.log(error.response);});
}
8 用户注册时短信验证码校验功能
8.1 注册时短信验证前端逻辑
8.1.1 register.html
<p class="form-row form-row-wide"><input style="width: 230px;" v-model="smscode" placeholder="短信验证码"@blur="check_smscode" name="msgcode"type="text" class="input-text" id="reg_mescode"><span class="error-tip" v-show="error_smscode">${error_smscode_msg}</span><a href="javascript:;" style="font-size: 16px;text-align: center;font-weight: normal;float: right" id="reg_mescode_btn"able="able" @click="send_smscode">${smscode_btn}</a>
</p>
8.1.2 register.js
check_smscode:function () {// 1.短信验证码格式校验let reg = /^\d{6}$/;if (!reg.test(this.smscode)) {this.error_smscode = true;} else {this.error_smscode = false;}// 2.⼀致性校验if (!this.error_smscode) {axios.get('/check_smscode/' + this.phone + '/?smscode=' + this.smscode, {responseType: 'json'}).then(response => {let code = response.data.code;if (code == '4001' || code == '4002' || code ==if (code == '4001' || code == '4002' || code == '4003') {this.error_smscode = true;this.error_smscode_msg =response.data.errormsg;} else {this.error_smscode = false;}})}
}
8.2 注册时短信验证后端逻辑
# verifications/views.py
class CheckSMScode(View):def get(self, request, phone):"""⽤户注册时短信验证码校验:param request::param phone::return:"""# 接收请求参数smscode_client = request.GET.get('smscode', '')# 校验参数if not all([phone, smscode_client]):return JsonResponse({'code': '4001', 'errormsg': '缺少必传参数'})# 查询服务器端短信验证码redis_conn = django_redis.get_redis_connection('verify_code')smscode_server = redis_conn.get('sms_%s' % phone)# 匹配(⾮空判断/有效性判断)if smscode_server is None:return JsonResponse({'code': '4002', 'errormsg': '短信验证码失效'})smscode_server = smscode_server.decode('utf-8')if smscode_client != smscode_server:return JsonResponse({'code': '4003', 'errormsg': '短信验证码不⼀致'})# 响应结果return JsonResponse({'code': '200', 'errormsg': 'OK'})
9 避免频繁发送短信验证码
存在的问题:
- 虽然我们在前端界⾯做了60秒倒计时功能。
- 但是恶意⽤户可以 绕过前端界⾯向后端频繁请求短信验证码。
解决办法:
- 在 后端也要限制 ⽤户请求短信验证码的频率。60秒内只允许⼀次请求短信 验证码。
- 在Redis数据库中缓存⼀个数值,有效期设置为60秒。
9.1 避免频繁发送短信验证码逻辑实现
9.1.1 提取并校验 is_send
is_send = redis_conn.get('is_send_%s' % phone)
if is_send:return JsonResponse({'code': 4001, 'error_msg': '发送短信过于频繁'})
9.1.2 is_send 、smscode 存⼊redis数据库
# 保存短信验证码
redis_conn.setex('sms_%s' % phone, 60, smscode)
# 保存is_send
redis_conn.setex('is_send_%s' % phone, 60, 1)
9.1.3 界⾯渲染 频繁发送短信提示信息
if (response.data.code == '4001') {this.error_smscode_msg = response.data.error_msg;this.error_smscode_code = true;
}
相关文章:

图片和短信验证码(头条项目-06)
1 图形验证码接口设计 将后端⽣成的图⽚验证码存储在redis数据库2号库。 结构: {img_uuid:0594} 1.1 创建验证码⼦应⽤ $ cd apps $ python ../../manage.py startapp verifications # 注册新应⽤ INSTALLED_APPS [django.contrib.admin,django.contrib.auth,…...
2501,wtl显示html
原文 在MFC程序中有专门封装的CHTMLView来显示超文本文件,如果在对话框中显示网页可用CDHTMLDialog,甚至可实现多页超文本向导风格的对话框,但是在WTL中却没有单独封装超文本的对应控件,这是因为COM组件的使用和编写本来就是ATL的强项,WTL扩展的是ATL欠缺的桌面应用的功能部分…...

嵌入式C语言:什么是指针?
目录 一、指针的基本概念 1.1. 定义指针 1.2. 赋值给指针 1.3. 解引用指针 1.4. 指针运算 1.5. 空指针 1.6. 函数参数 1.7. 数组和指针 1.8. 示例代码 二、指针在内存中的表示 2.1. 内存地址存储 2.2. 内存模型 2.3. 指针与硬件交互 2.4. 示例代码 三 、指针的重…...
解锁 KaiwuDB 数据库工程师,开启进阶之路
解锁 KaiwuDB 数据库工程师试题,开启进阶之路 一、KaiwuDB 数据库全方位洞察 (一)核心特性深度解析 原生分布式架构:摒弃传统集中式存储的局限,KaiwuDB 采用原生分布式架构,将数据分散存于多个节点。这不仅能有效避免单点故障风险,保障数据的高可用性,还能凭借并行处…...

ffmpeg7.0 aac转pcm
#pragma once #define __STDC_CONSTANT_MACROS #define _CRT_SECURE_NO_WARNINGSextern "C" { #include "libavcodec/avcodec.h" }//缓冲区大小(缓存5帧数据) #define AUDIO_INBUF_SIZE 40960 /*name depthu8 8s16 …...
【Pandas】pandas Series rdiv
Pandas2.2 Series Binary operator functions 方法描述Series.add()用于对两个 Series 进行逐元素加法运算Series.sub()用于对两个 Series 进行逐元素减法运算Series.mul()用于对两个 Series 进行逐元素乘法运算Series.div()用于对两个 Series 进行逐元素除法运算Series.true…...
线程安全问题介绍
文章目录 **什么是线程安全?****为什么会出现线程安全问题?****线程安全问题的常见场景****如何解决线程安全问题?**1. **使用锁**2. **使用线程安全的数据结构**3. **原子操作**4. **使用volatile关键字**5. **线程本地存储**6. **避免死锁*…...
为AI聊天工具添加一个知识系统 之27 支持边缘计算设备的资源存储库及管理器
本文问题 现在我们回到 ONE/TWO/TREE 的资源存储库 的设计--用来指导 足以 支持 本项目(为AI聊天工具增加一套知识系统)的 核心能力 “语言处理” 中 最高难度系数的“自然语言处理” 中最具挑战性的“含糊性” 问题的解决。--因为足以解决 自然语言中最…...
初识verilog HDL
为什么选择用Verilog HDL开发FPGA??? 硬件描述语言(Hardware Descriptipon Lagnuage,HDL)通过硬件的方式来产生与之对应的真实的硬件电路,最终实现所设计的预期功能,其设计方法与软件…...

VS2015 + OpenCV + OnnxRuntime-Cpp + YOLOv8 部署
近期有个工作需求是进行 YOLOv8 模型的 C 部署,部署环境如下 系统:WindowsIDE:VS2015语言:COpenCV 4.5.0OnnxRuntime 1.15.1 0. 预训练模型保存为 .onnx 格式 假设已经有使用 ultralytics 库训练并保存为 .pt 格式的 YOLOv8 模型…...

Notepad++上NppFTP插件的安装和使用教程
一、NppFTP插件下载 图示是已经安装好了插件。 在搜索框里面搜NppFTP,一般情况下,自带的下载地址容易下载失败。这里准备了一个下载连接:Release v0.29.10 ashkulz/NppFTP GitHub 这里我下载的是x86版本 下载好后在nodepad的插件里面选择打…...
Kotlin | Android Provider 的实现案例
目标 使用 Android Room 实现持久化库。 代码 Kotlin 代码编写 DemoDatabase,在build生成 DemoDatabase_Impl 疑问 Provider的数据会存在设备吗? 内部存储: 当使用 Room 创建数据库(如 DemoDatabase),数据库文件通常…...
频域自适应空洞卷积FADC详解
定义与原理 在探讨FADC的核心策略之前,我们需要深入了解其定义和工作原理。FADC是一种创新性的卷积技术,旨在克服传统空洞卷积的局限性。其核心思想是从 频谱分析的角度 改进空洞卷积,通过 动态调整膨胀率 来平衡有效带宽和感受野大小。 FADC的工作原理可以从以下几个方面…...

Edge浏览器内置的截长图功能
Edge浏览器内置截图功能 近年来,Edge浏览器不断更新和完善,也提供了长截图功能。在Edge中,只需点击右上角的“...”,然后选择“网页捕获”->“捕获整页”,即可实现长截图。这一功能的简单易用,使其成为…...

GAN的应用
5、GAN的应用 GANs是一个强大的生成模型,它可以使用随机向量生成逼真的样本。我们既不需要知道明确的真实数据分布,也不需要任何数学假设。这些优点使得GANs被广泛应用于图像处理、计算机视觉、序列数据等领域。上图是基于GANs的实际应用场景对不同G…...
Math Reference Notes: 希腊字母表
希腊字母(Greek alphabet)是古希腊语使用的字母系统,也是西方字母系统的先驱之一,广泛应用于现代数学、物理学、工程学以及各种科学领域。希腊字母有24个字母,它们分为大写和小写两种形式。 1. Alpha (Α, α) 发音&a…...

高通,联发科(MTK)等手机平台调优汇总
一、常见手机型号介绍: ISP除了用在安防行业,还有手机市场,以及目前新型的A/VR眼睛,机器3D视觉机器人,医疗内窥镜这些行业。 下面是一些最近几年发布的,,,旗舰SOC型号: 1.联发科:天玑92…...

Rust语言使用iced实现简单GUI页面
使用cargo新建一个rust项目 cargo new gui_demo cd gui_demo 编辑Cargo.toml文件 ,添加iced依赖 [package] name "gui_demo" version "0.1.0" edition "2021"[dependencies] iced "0.4.2" 编辑src/main.rs文件: u…...

使用wav2vec 2.0进行音位分类任务的研究总结
使用wav2vec 2.0进行音位分类任务的研究总结 原文名称: Using wav2vec 2.0 for phonetic classification tasks: methodological aspects 研究背景 自监督学习在语音中的应用 自监督学习在自动语音识别任务中表现出色,例如说话人识别和验证。变换器模型…...
25/1/11 嵌入式笔记<esp32> 初入esp32
用Arduino平台,学习了点亮led灯。 //定义LED引脚 int led_pin 12;void setup() {//设定引脚为输出模式pinMode(led_pin,OUTPUT):}void loop() {// 点亮LED:digitalWrite(led_pin,HIGH);//延时1sdelay(1000);//熄灭LEDdigitalWrite(led_pin,LOW)://延时…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅
目录 前言 操作系统与驱动程序 是什么,为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中,我们在使用电子设备时,我们所输入执行的每一条指令最终大多都会作用到硬件上,比如下载一款软件最终会下载到硬盘上&am…...