概述:
- 短信验证码的发送需要限制验证码的发送间隔不能不停的发,因为测试时发送的验证码是要花钱的,不可能不花钱就办事
- 短信验证码要根据图片验证码是不是正确再进行发,
进行短信验证码的实验要测试容联云平台;然后将短信验证码的类设置为单例模式(每次实例化都是用的一个地址,不会产生新的类) - 1.容联云平台:
- 2.单例模式
- 3.验证码相关逻辑与实现位置
容联云平台测试:
http://yuntongxun.com/member/main
点击开发文档,可以查看相关的开发文档,
在这里主要用到的就是短信开发手册
http://doc.yuntongxun.com/space/5a5098313b8496dd00dcdd7f
以下为容联云平台的python SDK
https://doc.yuntongxun.com/p/5f029ae7a80948a1006e776e
调用示例:
使用前先要安装ronglian_sms_sdk
pip install ronglian_sms_sdk
from ronglian_sms_sdk import SmsSDK
accId = '容联云通讯分配的主账号ID'
accToken = '容联云通讯分配的主账号TOKEN'
appId = '容联云通讯分配的应用ID'
def send_message():
sdk = SmsSDK(accId, accToken, appId)
tid = '容联云通讯创建的模板ID'
mobile = '手机号1,手机号2'
datas = ('变量1', '变量2')
resp = sdk.sendMessage(tid, mobile, datas)
print(resp)
说明下,其中的datas对应的是短信模板里的1和2
登录验证模版您的验证码为{1},请于{2}内正确输入,如非本人操作,请忽略此短信。
- 单例模式:
class CCP(object):
"""发送短信的单例类"""
# _instance = None
def __new__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
cls._instance = super().__new__(cls, *args, **kwargs)
#cls._instance.sdk = SmsSDK(accId, accToken, appId)
return cls._instance
a = CCP()
print(id(a))
b = CCP()
print(id(b))
通过这样的方式获得的实例共用一个空间
如果采用传统方式,则每个实例占一个空间,实例不再列举
短信验证码发送:
在libs中新建包:ronglianyun,新建ccp_sms.py文件,在其中新建发送模板的单例类
from ronglian_sms_sdk import SmsSDK
import json
accId = '8a216dxxxxxxxxxxxxxx'
accToken = 'xxxxxxxxxxxxxxxx'
appId = 'xxxxxxxxxxxxxxxxxxxxxxxxxxx'
class CCP(object):
"""发送短信的单例类"""
# _instance = None
def __new__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
cls._instance = super().__new__(cls, *args, **kwargs)
cls._instance.sdk = SmsSDK(accId, accToken, appId)
return cls._instance
def send_message(self, mobile, datas, tid):
sdk = self._instance.sdk
resp = sdk.sendMessage(tid, mobile, datas)
result = json.loads(resp)
if result['statusCode'] == '000000':
return 0
else:
return -1
然后在蓝图verify_code.py新建路由:
@api.route("/sms_codes/<re(r'1[345678]\d{9}'):mobile>")
def get_sms_code(mobile):
"""获取短信验证码"""
# 获取参数
# 图片验证码
image_code = request.args.get('image_code')
# UUID
image_code_id = request.args.get('image_code_id')
# 校验参数
if not all([image_code, image_code_id]):
return jsonify(errno=RET.PARAMERR, errmsg='参数不完整')
# 业务逻辑
# 从redis中取出验证码
try:
real_image_code = redis_store.get('image_code_%s' % image_code_id)
except Exception as e:
logging.error(e)
return jsonify(errno=RET.DBERR, errmsg='redis数据库异常')
# 判断图片验证码是否过期
if real_image_code is None:
return jsonify(errno=RET.NODATA, errmsg='图片验证码失效')
# 删除redis中的图片验证码
try:
redis_store.delete('image_code_%s' % image_code_id)
except Exception as e:
logging.error(e)
# print(real_image_code) b'RVMJ'
# 与用户填写的图片验证码对比
real_image_code = real_image_code.decode()
if real_image_code.lower() != image_code.lower():
return jsonify(errno=RET.DATAERR, errmsg='图片验证码错误')
# 判断手机号的操作
try:
send_flag = redis_store.get('send_sms_code_%s' % mobile)
except Exception as e:
logging.error(e)
else:
if send_flag is not None:
return jsonify(errno=RET.REQERR, errmsg='请求过于频繁')
# 判断手机号是否存在
try:
user = User.query.filter_by(mobile=mobile).first()
except Exception as e:
logging.error(e)
else:
if user is not None:
# 表示手机号已经被注册过
return jsonify(errno=RET.DATAEXIST, errmsg='手机号已经存在')
# 生成短信验证码
sms_code = "%06d" % random.randint(0, 999999)
# 保存真实的短信验证码到redis
try:
# redis管道
pl = redis_store.pipeline()
pl.setex("sms_code_%s" % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
# 保存发送给这个手机号的记录
pl.setex('send_sms_code_%s' % mobile, constants.SNED_SMS_CODE_EXPIRES, 1)
pl.execute()
except Exception as e:
logging.error(e)
return jsonify(errno=RET.DBERR, errmsg='保存短信验证码异常')
# 发短信
try:
ccp = CCP()
result = ccp.send_message(mobile, (sms_code, int(constants.SMS_CODE_REDIS_EXPIRES/60)), 1)
except Exception as e:
logging.error(e)
return jsonify(errno=RET.THIRDERR, errmsg='发送异常')
# 返回值
if result == 0:
return jsonify(errno=RET.OK, errmsg='发送成功')
else:
return jsonify(errno=RET.THIRDERR, errmsg='发送失败')