图片和短信验证码(头条项目-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 请求参数:路径参数
参数名类型是否必传说明
uuidstring唯⼀编号
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 请求参数:路径参数和查询字符串
参数名类型是否必传说明
phonestring⼿机号
imgcodestring图⽚验证码
uuidstring唯⼀编号
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 知识要点

  1. 保存短信验证码是为注册做准备的。
  2. 为了避免⽤户使⽤图形验证码恶意测试后端提取了图形验证码后,⽴即删除图形验证码
  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;
}

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

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

相关文章

SpringCloud系列教程:微服务的未来(十二)OpenFeign连接池、最佳实践、日志、微服务拆分

本篇博客将讨论如何优化 OpenFeign 的连接池配置&#xff0c;如何使用最佳实践提升服务间通信的效率和可维护性&#xff0c;并探讨如何通过拆分服务来提升微服务架构的灵活性和可扩展性&#xff0c;具体涵盖了用户服务和交易服务的拆分。 目录 前言 OpenFeign 连接池 最佳实…

进阶——十六届蓝桥杯嵌入式熟练度练习(LED的全开,全闭,点亮指定灯,交替闪烁,PWM控制LED呼吸灯)

点亮灯的函数 void led_show(unsigned char upled) { HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOC,upled<<8,GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RE…

动态规划【打家劫舍】

今天和大家分享一下动态规划当中的打家劫舍题目&#xff0c;希望在大家刷题的时候提供一些思路 打家劫舍1&#xff1a; 题目链接&#xff1a; 198. 打家劫舍 - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋…

Jaeger UI使用、采集应用API排除特定路径

Jaeger使用 注&#xff1a; Jaeger服务端版本为&#xff1a;jaegertracing/all-in-one-1.6.0 OpenTracing版本为&#xff1a;0.33.0&#xff0c;最后一个版本&#xff0c;停留在May 06, 2019。最好升级到OpenTelemetry。 Jaeger客户端版本为&#xff1a;jaeger-client-1.3.2。…

Vue-Cli

一.vue.js 1.优点 1)体积小,压缩后33K 2)更高的运行效率 3)双向数据绑定 4)生态丰富,学习成本低 2.Vue指令 指令带有前缀 v- 开头&#xff0c;以表示它们是 Vue 提供的特殊属性。 1)v-text (1)作用 &#xff1a;设置标签的文本内容 默认写法会替换全部内容&#xff0c…

【源码解析】Java NIO 包中的 ByteBuffer

文章目录 1. 前言2. ByteBuffer 概述3. 属性4. 构造器5. 方法5.1 allocate 分配 Buffer5.2 wrap 映射数组5.3 slice 获取子 ByteBuffer5.4 duplicate 复刻 ByteBuffer5.5 asReadOnlyBuffer 创建只读的 ByteBuffer5.6 get 方法获取字节5.7 put 方法往 ByteBuffer 里面加入字节5.…

HTML5实现好看的中秋节网页源码

HTML5实现好看的中秋节网页源码 前言一、设计来源1.1 网站首页界面1.2 登录注册界面1.3 节日由来界面1.4 节日习俗界面1.5 节日文化界面1.6 节日美食界面1.7 节日故事界面1.8 节日民谣界面1.9 联系我们界面 二、效果和源码2.1 动态效果2.2 源代码 源码下载结束语 HTML5实现好看…

OA项目登录

导入依赖,下面的依赖是在这次OA登录中用到的 <!--web依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.sprin…

YangQG 面试题汇总

一、交叉链表 问题&#xff1a; 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 解题思想&#xff1a; 双指针 备注&#xff1a;不是快慢指针&#xff0c;如果两个长度相…

【面试题】技术场景 4、负责项目时遇到的棘手问题及解决方法

工作经验一年以上程序员必问问题 面试题概述 问题为在负责项目时遇到的棘手问题及解决方法&#xff0c;主要考察开发经验与技术水平&#xff0c;回答不佳会影响面试印象。提供四个回答方向&#xff0c;准备其中一个方向即可。 1、设计模式应用方向 以登录为例&#xff0c;未…

WEB前端-3.2

目录 css 【例】飙升榜 【源码】 css 【例】飙升榜 【源码】 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"&g…

qml SpringAnimation详解

1. 概述 SpringAnimation 是 Qt Quick 中用于模拟弹簧效果的动画类。它通过模拟物体在弹簧力作用下的反应&#xff0c;产生一种振荡的动画效果&#xff0c;常用于模拟具有自然回弹、弹性和振动的动态行为。这种动画效果在 UI 中广泛应用&#xff0c;特别是在拖动、拉伸、回弹等…

新活动平台建设历程与架构演进

01 前言 历时近两年的重新设计和迭代重构&#xff0c;用户技术中心的新活动平台建设bilibili活动中台终于落地完成&#xff01;并迎来了里程碑时刻 —— 接过新老迭代的历史交接棒&#xff0c;从内到外、从开发到搭建实现全面升级&#xff0c;开启了活动生产工业化新时代&#…

Python学习(三)基础入门(数据类型、变量、条件判断、模式匹配、循环)

目录 一、第一个 Python 程序1.1 命令行模式、Python 交互模式1.2 Python的执行方式1.3 SyntaxError 语法错误1.4 输入和输出 二、Python 基础2.1 Python 语法2.2 数据类型1&#xff09;Number 数字2&#xff09;String 字符串3&#xff09;List 列表4&#xff09;Tuple 元组5&…

微信小程序用的SSL证书有什么要求吗?

微信小程序主要建立在手机端使用&#xff0c;然而手机又涉及到各种系统及版本&#xff0c;所以对SSL证书也有要求&#xff0c;如果要小程序可以安全有效的访问需要满足以下要求&#xff1a; 1、原厂SSL证书&#xff08;原厂封&#xff09;。 2、DV单域名或者DV通配符。 3、兼…

【excel】VBA简介(Visual Basic for Applications)

文章目录 一、基本概念二、语法2.1 数据类型2.11 基本数据类型2.12 常量2.13 数组 2.2 控制语句2.21 条件语句2.22 循环语句2.23 错误处理&#xff1a;On Error2.24 逻辑运算 2.3 其它语句2.31 注释2.32 with语句 2.4 表达式2.41 常见表达式类型2.42 表达式的优先级 2.5 VBA 的…

回溯算法汇总

1.回溯算法 回溯是递归的副产品&#xff0c;只要有递归就会有回溯。 回溯的本质是穷举&#xff0c;穷举所有可能&#xff0c;然后选出我们想要的答案&#xff0c;如果想让回溯法高效一些&#xff0c;可以加一些剪枝的操作&#xff0c;但也改不了回溯法就是穷举的本质。 回溯…

【黑马程序员三国疫情折线图——json+pyechart=数据可视化】

json数据在文末 将海量的数据处理成我们肉眼可以进行分析的形式&#xff0c;数据的可视化&#xff0c;可以分为两个步骤&#xff1a; 数据处理&#xff1a;利用三方网站厘清json层次格式化&#xff0c;再对文件的读取、检查是否符合JSON规范以及规范化、JSON格式的转化&#…

Node.js——fs(文件系统)模块

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

注册中心如何选型?Eureka、Zookeeper、Nacos怎么选

这是小卷对分布式系统架构学习的第9篇文章&#xff0c;第8篇时只回答了注册中心的工作原理的内容&#xff0c;面试官的第二个问题还没回答&#xff0c;今天再来讲讲各个注册中心的原理&#xff0c;以及区别&#xff0c;最后如何进行选型 上一篇文章&#xff1a;如何设计一个注册…