【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如何快速精准抓取网页数据

《一文教你Python如何快速精准抓取网页数据》这篇文章主要为大家详细介绍了如何利用Python实现快速精准抓取网页数据,文中的示例代码简洁易懂,具有一定的借鉴价值,有需要的小伙伴可以了解下... 目录1. 准备工作2. 基础爬虫实现3. 高级功能扩展3.1 抓取文章详情3.2 保存数据到文件4. 完整示例

使用Python实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

基于Python打造一个智能单词管理神器

《基于Python打造一个智能单词管理神器》这篇文章主要为大家详细介绍了如何使用Python打造一个智能单词管理神器,从查询到导出的一站式解决,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 项目概述:为什么需要这个工具2. 环境搭建与快速入门2.1 环境要求2.2 首次运行配置3. 核心功能使用指

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句

利用Python打造一个Excel记账模板

《利用Python打造一个Excel记账模板》这篇文章主要为大家详细介绍了如何使用Python打造一个超实用的Excel记账模板,可以帮助大家高效管理财务,迈向财富自由之路,感兴趣的小伙伴快跟随小编一... 目录设置预算百分比超支标红预警记账模板功能介绍基础记账预算管理可视化分析摸鱼时间理财法碎片时间利用财

Python中的Walrus运算符分析示例详解

《Python中的Walrus运算符分析示例详解》Python中的Walrus运算符(:=)是Python3.8引入的一个新特性,允许在表达式中同时赋值和返回值,它的核心作用是减少重复计算,提升代码简... 目录1. 在循环中避免重复计算2. 在条件判断中同时赋值变量3. 在列表推导式或字典推导式中简化逻辑

python处理带有时区的日期和时间数据

《python处理带有时区的日期和时间数据》这篇文章主要为大家详细介绍了如何在Python中使用pytz库处理时区信息,包括获取当前UTC时间,转换为特定时区等,有需要的小伙伴可以参考一下... 目录时区基本信息python datetime使用timezonepandas处理时区数据知识延展时区基本信息

Python位移操作和位运算的实现示例

《Python位移操作和位运算的实现示例》本文主要介绍了Python位移操作和位运算的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 位移操作1.1 左移操作 (<<)1.2 右移操作 (>>)注意事项:2. 位运算2.1

使用Python和Pyecharts创建交互式地图

《使用Python和Pyecharts创建交互式地图》在数据可视化领域,创建交互式地图是一种强大的方式,可以使受众能够以引人入胜且信息丰富的方式探索地理数据,下面我们看看如何使用Python和Pyec... 目录简介Pyecharts 简介创建上海地图代码说明运行结果总结简介在数据可视化领域,创建交互式地