【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

相关文章

Python将博客内容html导出为Markdown格式

《Python将博客内容html导出为Markdown格式》Python将博客内容html导出为Markdown格式,通过博客url地址抓取文章,分析并提取出文章标题和内容,将内容构建成html,再转... 目录一、为什么要搞?二、准备如何搞?三、说搞咱就搞!抓取文章提取内容构建html转存markdown

Python获取中国节假日数据记录入JSON文件

《Python获取中国节假日数据记录入JSON文件》项目系统内置的日历应用为了提升用户体验,特别设置了在调休日期显示“休”的UI图标功能,那么问题是这些调休数据从哪里来呢?我尝试一种更为智能的方法:P... 目录节假日数据获取存入jsON文件节假日数据读取封装完整代码项目系统内置的日历应用为了提升用户体验,

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

Python Websockets库的使用指南

《PythonWebsockets库的使用指南》pythonwebsockets库是一个用于创建WebSocket服务器和客户端的Python库,它提供了一种简单的方式来实现实时通信,支持异步和同步... 目录一、WebSocket 简介二、python 的 websockets 库安装三、完整代码示例1.

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

Python使用自带的base64库进行base64编码和解码

《Python使用自带的base64库进行base64编码和解码》在Python中,处理数据的编码和解码是数据传输和存储中非常普遍的需求,其中,Base64是一种常用的编码方案,本文我将详细介绍如何使... 目录引言使用python的base64库进行编码和解码编码函数解码函数Base64编码的应用场景注意

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优