【Python百日进阶-WEB开发】Day179 - Django案例:11短信验证码

2024-02-13 22:30

本文主要是介绍【Python百日进阶-WEB开发】Day179 - Django案例:11短信验证码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 九、短信验证码
    • 9.1 短信验证码逻辑分析
    • 9.2 容联云通讯短信平台
      • 9.2.1 容联云通讯短信平台介绍
      • 9.2.2 容联云通讯短信SDK测试
        • 9.2.2.1 美多商城meiduo_mall.apps.verifications.libs中新建yuntongxun包,结构如下:
        • 9.2.2.2 ccp_sms.py代码
        • 9.2.2.3 CCPRestSDK.py ,python3代码
        • 9.2.2.4 测试发送短信
      • 9.2.3 封装发送短信单例类
    • 9.3 短信验证码接口设计和定义
    • 9.4 短信验证码后端逻辑
    • 9.5 短信验证码前端逻辑

九、短信验证码

9.1 短信验证码逻辑分析

在这里插入图片描述

9.2 容联云通讯短信平台

了解容联云通讯平台和短信SDK的使用方式,

9.2.1 容联云通讯短信平台介绍

  1. 容联云官网:https://www.yuntongxun.com/
    在这里插入图片描述
    2.注册登录
    在这里插入图片描述
  2. 通过认证,企业认证或个人认证,提交申请后一般需要第二天通过。发送短信0.06元/条,注册赠送8元,我发过一条了。
    在这里插入图片描述
  3. 添加容联云子应用,通过认证后可以上线应用
    在这里插入图片描述
  4. 添加测试号码
    在这里插入图片描述
  5. 短信模板
    在这里插入图片描述
  6. Python Demo中模板短信的使用说明
    https://doc.yuntongxun.com/p/5a533e0c3b8496dd00dce08c
    在这里插入图片描述
  7. 开发文档-SDK接口文件
    https://www.yuntongxun.com/doc/ready/demo/1_4_1_2.html
    在这里插入图片描述

9.2.2 容联云通讯短信SDK测试

9.2.2.1 美多商城meiduo_mall.apps.verifications.libs中新建yuntongxun包,结构如下:

在这里插入图片描述

9.2.2.2 ccp_sms.py代码
#-*- coding: UTF-8 -*-  from meiduo_mall.apps.verifications.libs.yuntongxun.CCPRestSDK import REST
# import ConfigParser
import ssl# 全局取消证书验证
ssl._create_default_https_context = ssl._create_unverified_context  #主帐号
accountSid= '8aaf07 这里填真实的主账号 5b0963df1';#主帐号Token
accountToken= 'b809 这里填真实的Token 4018733';#应用Id
appId='8a21 这里填真实的AppID 10d53ba6';#请求地址,格式如下,不需要写http://
serverIP='app.cloopen.com';#请求端口 
serverPort='8883';#REST版本号
softVersion='2013-12-26';# 发送模板短信# @param to 手机号码# @param datas 内容数据 格式为数组 例如:{'12','34'},如不需替换请填 ''# @param $tempId 模板Iddef sendTemplateSMS(to,datas,tempId):#初始化REST SDKrest = REST(serverIP,serverPort,softVersion)rest.setAccount(accountSid,accountToken)rest.setAppId(appId)result = rest.sendTemplateSMS(to,datas,tempId)print(result)#sendTemplateSMS(手机号码,内容数据,模板Id)
if __name__ == '__main__':# 注意测试的短信模板编号为1,短信验证码为123456,有效期为5分钟sendTemplateSMS('13953800865', ['123456', 5], 1)
9.2.2.3 CCPRestSDK.py ,python3代码

这个文件官网示例文件使用python2.7写的,有五六个地方需要修改,这是修改测试过的python3代码
修改内容主要包括:
1、头部导包
2、MD5加密
3、req.add_data
4、base64加密等

from hashlib import md5
import base64
import datetime
import urllib.request	# py3
import json
from meiduo_mall.apps.verifications.libs.yuntongxun.xmltojson import xmltojson	# py3
from xml.dom import minidom class REST:AccountSid=''AccountToken=''AppId=''SubAccountSid=''SubAccountToken=''ServerIP=''ServerPort=''SoftVersion=''Iflog=True #是否打印日志Batch=''  #时间戳BodyType = 'xml'#包体格式,可填值:json 、xml# 初始化# @param serverIP       必选参数    服务器地址# @param serverPort     必选参数    服务器端口# @param softVersion    必选参数    REST版本号def __init__(self,ServerIP,ServerPort,SoftVersion):self.ServerIP = ServerIP;self.ServerPort = ServerPort;self.SoftVersion = SoftVersion;# 设置主帐号# @param AccountSid  必选参数    主帐号# @param AccountToken  必选参数    主帐号Tokendef setAccount(self,AccountSid,AccountToken):self.AccountSid = AccountSid;self.AccountToken = AccountToken;   # 设置子帐号# # @param SubAccountSid  必选参数    子帐号# @param SubAccountToken  必选参数    子帐号Tokendef setSubAccount(self,SubAccountSid,SubAccountToken):self.SubAccountSid = SubAccountSid;self.SubAccountToken = SubAccountToken;    # 设置应用ID# # @param AppId  必选参数    应用IDdef setAppId(self,AppId):self.AppId = AppId; def log(self,url,body,data):print('这是请求的URL:')print (url);print('这是请求包体:')print (body);print('这是响应包体:')print (data);print('********************************')# 创建子账号# @param friendlyName   必选参数      子帐号名称def CreateSubAccount(self, friendlyName):self.accAuth()nowdate = datetime.datetime.now()self.Batch = nowdate.strftime("%Y%m%d%H%M%S")#生成sigsignature = self.AccountSid + self.AccountToken + self.Batch;signature = signature.encode('utf-8') # py3# sig = md5.new(signature).hexdigest().upper()sig = md5(signature).hexdigest().upper() # py3#拼接URLurl = "https://"+self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/SubAccounts?sig=" + sig#生成authsrc = self.AccountSid + ":" + self.Batch;# auth = base64.encodestring(src).strip()auth = base64.encodestring(src.encode()).strip() 	# py3req = urllib.request.Request(url)self.setHttpHeader(req)req.add_header("Authorization", auth)#xml格式body ='''<?xml version="1.0" encoding="utf-8"?><SubAccount><appId>%s</appId>\<friendlyName>%s</friendlyName>\</SubAccount>\'''%(self.AppId, friendlyName)if self.BodyType == 'json': #json格式body = '''{"friendlyName": "%s", "appId": "%s"}'''%(friendlyName,self.AppId)data=''# req.add_data(body)req.data = body.encode() # py3try:res = urllib.request.urlopen(req);data = res.read()res.close()if self.BodyType=='json':#json格式locations = json.loads(data)else:#xml格式xtj=xmltojson()locations=xtj.main(data)if self.Iflog:self.log(url,body,data)return locationsexcept Exception as error:if self.Iflog:self.log(url,body,data)return {'172001':'网络错误'}
9.2.2.4 测试发送短信

1.vscode终端输出
在这里插入图片描述

  1. 测试手机收到的短信
    在这里插入图片描述

9.2.3 封装发送短信单例类

问题:如果同时发送多个短信验证码,那么就会同时创建多个RET SDK的对象,会消耗很多额外的内存空间。
解决方法:使用单例类,它的特点是只有一个实例存在
使用场景:当我们希望在整个系统中,某个类只出现一个实例时,就可以使用单例类设计模式
改写后的代码:

#-*- coding: UTF-8 -*-  from meiduo_mall.apps.verifications.libs.yuntongxun.CCPRestSDK import REST
# import ConfigParser
import ssl# 全局取消证书验证
ssl._create_default_https_context = ssl._create_unverified_context  #主帐号
accountSid= '8aaf07087a331dc7017afb85b0963df1';
#主帐号Token
accountToken= 'b809c84015db41c8a4a3d84224018733';
#应用Id
appId='8a216da87a332d53017afb8d10d53ba6';
#请求地址,格式如下,不需要写http://
serverIP='app.cloopen.com';
#请求端口 
serverPort='8883';
#REST版本号
softVersion='2013-12-26';
# 发送模板短信
# @param to 手机号码
# @param datas 内容数据 格式为数组 例如:{'12','34'},如不需替换请填 ''
# @param $tempId 模板Id# def sendTemplateSMS(to,datas,tempId):
#     #初始化REST SDK
#     rest = REST(serverIP,serverPort,softVersion)
#     rest.setAccount(accountSid,accountToken)
#     rest.setAppId(appId)#     result = rest.sendTemplateSMS(to,datas,tempId)
#     print(result)class CCP(object):""" 发送短信验证码的单例类 """def __new__(cls, *args, **kwargs):""" 定义单例化的初始化方法,返回值为单例 """# 判断单例是否存在,利用动态赋值的_instance属性。如果单例不存在,就初始化单例if not hasattr(cls, '_instance'):cls._instance = super(CCP, cls).__new__(cls, *args, **kwargs)#初始化REST SDK,赋值给单例属性,实现与单例同生共死,唯一存在cls._instance.rest = REST(serverIP,serverPort,softVersion)cls._instance.rest.setAccount(accountSid,accountToken)cls._instance.rest.setAppId(appId)# 返回单例return cls._instance  def send_template_sms(self, to, datas, tempId):""" 定义对象方法,发送短信验证码 to:手机号码,字符串,多个手机号码用逗号分隔datas:发送内容,双元素列表,第一个元素为验证码字符串,第二个元素为整数有效时间(分钟)tempID:模板ID,测试模板为1返回值:成功:0,失败:-1"""result = self.rest.sendTemplateSMS(to,datas,tempId)print(result)# 根据发送是否成功返回0或-1if result.get('statusCode') == '000000':return 0else:return -1#sendTemplateSMS(手机号码,内容数据,模板Id)
if __name__ == '__main__':# 注意测试的短信模板编号为1,短信验证码为123456,有效期为5分钟# sendTemplateSMS('13953800865', ['123456', 5], 1)# 单例类发送短信验证码CCP().send_template_sms('13953800865', ['6543258', 5], 1)

9.3 短信验证码接口设计和定义

在这里插入图片描述

9.4 短信验证码后端逻辑

  1. verifications.urls.py中
from django.urls import path, re_path
from . import viewsapp_name = 'verifications'urlpatterns = [# 图形验证码,re_path路由正则校验,响应json数据,不需要重定向,也就不需要命名空间re_path(r'^image_codes/(?P<uuid>[\w-]+)/$', views.ImageCodeView.as_view()),# 短信验证码,re_path路由正则校验,响应json数据,不需要重定向,也就不需要命名空间re_path(r'^sms_codes/(?P<mobile>1[3-9]\d{9})/$', views.SMSCodeView.as_view()),]
  1. verifications.views.py中的短信验证码类视图
from django.views import View
from django_redis import get_redis_connection
from django import http
import random, loggingfrom meiduo_mall.apps.verifications.libs.captcha.captcha import captcha
from . import constants
from meiduo_mall.utils.response_code import RETCODE
from meiduo_mall.apps.verifications.libs.yuntongxun.ccp_sms import CCP# 创建日志输出器
logger = logging.getLogger('django')class SMSCodeView(View):""" 短信验证码 """def get (self, request, mobile):"""param:request,请求对象;mobile,手机号return:JSON"""""" 接收和校验参数 """# 接收参数image_code_client = request.GET.get('image_code')uuid = request.GET.get('uuid')# 校验参数,mobile不需要视图内校验,在路由处已经校验完毕了,错误进不了视图if not all([image_code_client, uuid]):return http.HttpResponseForbidden('缺少必传参数!')# 判断用户是否频繁发送短信验证码redis_conn = get_redis_connection('verify_code')     # 创建redis库的连接send_flag = redis_conn.get(f'send_flag_{mobile}')if send_flag:   #  已存在return http.JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '发送短信验证码过于频繁!'})"""" 主体业务逻辑 """# 1.从redis库中提取图形验证码image_code_server = redis_conn.get(f'img_{uuid}')if image_code_server is None:return http.JsonResponse({'code': RETCODE.IMAGECODEERR, 'errmsg': '图形验证码已失效!'})# 2.删除redis中存储的图形验证码redis_conn.delete(f'img_{uuid}')# 3.对比图形验证码image_code_server = image_code_server.decode()   # 提取的数据时bytes类型,需要转换为字符串if image_code_client.lower() != image_code_server.lower():  # 全部转为小写return http.JsonResponse({'code': RETCODE.IMAGECODEERR, 'errmsg': '输入图形验证码有误!'})# 4.生成短信验证码:随机6位数字,不足前面补0, 000007sms_code = '%06d' % random.randint(0, 999999)logger.info(sms_code)   # 手动输出短信验证码的日志# 5.保存短信验证码,为优化redis的性能,使用管道队列操作# 5.1 创建redis pipeline管道队列pl = redis_conn.pipeline()# 5.2 将命令添加到队列中pl.setex(f'sms_{mobile}', constants.SMS_CODE_REDIS_EXPIRES, sms_code)   # sms_code存储到redis数据库pl.setex(f'send_flag_{mobile}', constants.SEND_SMS_CODE_INTERVAL, 1)    # 保存短信验证码标记,有效期60秒,标记1表示60秒内给该手机发送了验证码# 5.3 执行队列命令pl.excute()# 6.单例类发送短信验证码CCP().send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES // 60], constants.SEND_SMS_TEMPLATE_ID)""" 响应结果 """return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '短信验证码发送成功!'})

9.5 短信验证码前端逻辑

  1. register.html中的短信验证码部分
<li><label for="">短信验证码</label><input type="text" v-model="sms_code" @blur="check_sms_code" name="sms_code" id="sms_code" class="msg_input"><a @click="send_sms_code" class="get_msg_code">[[ sms_code_tip ]]</a><span class="error_tip" v-show="error_sms_code">[[ error_sms_code_message]]</span>
</li>
  1. register.js中的方法
//发送手机验证码
send_sms_code(){//避免恶意用户频繁点击获取短信验证码的A标签if (this.send_flag == true) {   //已经点击了发送短信验证码return;}this.send_flag = true;      //校验用户输入的mobile和image_codethis.check_mobile();this.check_image_code();if (this.error_image_code == true || this.error_mobile == true) {this.send_flag == false;return;}//?后面为查询字符串参数let url = '/sms_codes/'+ this.mobile +'/?image_code=' + this.image_code + '&uuid=' + this.uuid;  axios.get(url, {responseType: 'json'}).then(response => {if (response.data.code == '0') {    //发送短信验证码成功//展示倒计时60S效果 setInterval('回调函数', '时间间隔1000毫秒')let num = 60;let t = setInterval(() => {     // t 为定时器编号if (num == 1){          //倒计时即将结束clearInterval(t);   // 停止回调函数的执行this.sms_code_tip = '获取短信验证码';   // 还原 sms_code_tip 的提示信息this.generate_image_code();     //重新生成图形验证码this.send_flag == false;} else {                // 正在倒计时num -= 1;this.sms_code_tip = num + '秒';}}, 1000)} else {    if (response.data.code == '4001') { // 图形验证码错误// 渲染错误信息this.error_image_code_message = response.data.errmsg;this.error_image_code = true;this.send_flag == false;}}}).catch(error => {console.log(error.response);this.send_flag == false;})
},

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这篇关于【Python百日进阶-WEB开发】Day179 - Django案例:11短信验证码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/706777

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

如何用Docker运行Django项目

本章教程,介绍如何用Docker创建一个Django,并运行能够访问。 一、拉取镜像 这里我们使用python3.11版本的docker镜像 docker pull python:3.11 二、运行容器 这里我们将容器内部的8080端口,映射到宿主机的80端口上。 docker run -itd --name python311 -p

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof