1.容联云官网
容联云通讯网址:https://www.yuntongxun.com/注册并登陆2.容联云管理控制台
3.容联云创建应用
4.应用申请上线,并进行资质认证
5.完成资质认证,应用成功上线
6.添加测试号码
7.短信模板
1.模板短信SDK下载
https://www.yuntongxun.com/doc/ready/demo/1_4_1_2.html2.模板短信SDK使用说明
http://doc.yuntongxun.com/p/5a533e0c3b8496dd00dce08c3.集成模板短信SDK
CCPRestSDK.py:由容联云通讯开发者编写的官方SDK文件,包括发送模板短信的方法ccp_sms.py:调用发送模板短信的方法集成模板下载:
链接:https://pan.baidu.com/s/1zWkwdybcnPpMjLbzHhvkBw
提取码:fwhz
4.模板短信SDK测试
ccp_sms.py文件中 # -*- coding:utf-8 -*- from verifications.libs.yuntongxun.CCPRestSDK import REST # 说明:主账号,登陆云通讯网站后,可在"控制台-应用"中看到开发者主账号ACCOUNT SID _accountSid = '8aaf070862181ad5016236f3bcc811d5' # 说明:主账号Token,登陆云通讯网站后,可在控制台-应用中看到开发者主账号AUTH TOKEN _accountToken = '4e831592bd464663b0de944df13f16ef' # 请使用管理控制台首页的APPID或自己创建应用的APPID _appId = '8aaf070868747811016883f12ef3062c' # 说明:请求地址,生产环境配置成app.cloopen.com _serverIP = 'sandboxapp.cloopen.com' # 说明:请求端口 ,生产环境为8883 _serverPort = "8883" # 说明:REST API版本号保持不变 _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) for k, v in result.items(): if k == 'templateSMS': for k, s in v.items(): print('%s:%s' % (k, s)) else: print('%s:%s' % (k, v)) if __name__ == '__main__': # 注意: 测试的短信模板编号为1 sendTemplateSMS('17600992168', ['123456', 5], 1)5.模板短信SDK返回结果说明
{ 'statusCode': '000000', // 状态码。'000000'表示成功,反之,失败 'templateSMS': { 'smsMessageSid': 'b5768b09e5bc4a369ed35c444c13a1eb', // 短信唯一标识符 'dateCreated': '20190125185207' // 短信发送时间 } }1.封装发送短信单例类
class CCP(object): """发送短信的单例类""" def __new__(cls, *args, **kwargs): # 判断是否存在类属性_instance,_instance是类CCP的唯一对象,即单例 if not hasattr(CCP, "_instance"): cls._instance = super(CCP, cls).__new__(cls, *args, **kwargs) cls._instance.rest = REST(_serverIP, _serverPort, _softVersion) cls._instance.rest.setAccount(_accountSid, _accountToken) cls._instance.rest.setAppId(_appId) return cls._instance2.封装发送短信单例方法
def send_template_sms(self, to, datas, temp_id): """ 发送模板短信单例方法 :param to: 注册手机号 :param datas: 模板短信内容数据,格式为列表,例如:['123456', 5],如不需替换请填 '' :param temp_id: 模板编号,默认免费提供id为1的模板 :return: 发短信结果 """ result = self.rest.sendTemplateSMS(to, datas, temp_id) if result.get("statusCode") == "000000": # 返回0,表示发送短信成功 return 0 else: # 返回-1,表示发送失败 return -13.测试单例类发送模板短信结果
if __name__ == '__main__':
# 注意: 测试的短信模板编号为1
CCP().send_template_sms('17600992168', ['123456', 5], 1)
1.请求方式
选项
方案
请求方法
GET
请求地址
/sms_codes/(?P<mobile>1[3-9]\d{9})/
2.请求参数:路径参数和查询字符串
参数名
类型
是否必传
说明
mobile
string
是
手机号
image_code
string
是
图形验证码
uuid
string
是
唯一编号
3.响应结果:JSON
字段
说明
code
状态码
errmsg
错误信息
1.register.html
<li> <label>短信验证码:</label> <input type="text" v-model="sms_code" @blur="check_sms_code" name="sms_code" id="msg_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>2.register.js
check_sms_code(){ if(this.sms_code.length != 6){ this.error_sms_code_message = '请填写短信验证码'; this.error_sms_code = true; } else { this.error_sms_code = false; } },1.发送短信验证码事件处理
send_sms_code(){ // 避免重复点击 if (this.sending_flag == true) { return; } this.sending_flag = true; // 校验参数 this.check_mobile(); this.check_image_code(); if (this.error_mobile == true || this.error_image_code == true) { this.sending_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') { // 倒计时60秒 var num = 60; var t = setInterval(() => { if (num == 1) { clearInterval(t); this.sms_code_tip = '获取短信验证码'; this.sending_flag = false; } else { num -= 1; // 展示倒计时信息 this.sms_code_tip = num + '秒'; } }, 1000, 60) } else { if (response.data.code == '4001') { this.error_image_code_message = response.data.errmsg; this.error_image_code = true; } else { // 4002 this.error_sms_code_message = response.data.errmsg; this.error_sms_code = true; } this.generate_image_code(); this.sending_flag = false; } }) .catch(error => { console.log(error.response); this.sending_flag = false; }) },存在的问题:
虽然我们在前端界面做了60秒倒计时功能。
但是恶意用户可以绕过前端界面向后端频繁请求短信验证码。
解决办法:
在后端也要限制用户请求短信验证码的频率。60秒内只允许一次请求短信验证码。
在Redis数据库中缓存一个数值,有效期设置为60秒。
1. 避免频繁发送短信验证码逻辑分析
2. 避免频繁发送短信验证码逻辑实现
1.提取、校验send_flag
send_flag = redis_conn.get('send_flag_%s' % mobile) if send_flag: return http.JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '发送短信过于频繁'})2.重新写入send_flag
# 保存短信验证码 redis_conn.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code) # 重新写入send_flag redis_conn.setex('send_flag_%s' % mobile, constants.SEND_SMS_CODE_INTERVAL, 1)3.界面渲染频繁发送短信提示信息
if (response.data.code == '4001') { this.error_image_code_message = response.data.errmsg; this.error_image_code = true; } else { // 4002 this.error_sms_code_message = response.data.errmsg; this.error_sms_code = true; }