美多商城项目之短信验证码

目前市面上可以发送短信验证码的平台有很多,此项目中使用的容联云通讯进行短信验证码的发送。

首先,我们先来进行手机验证码的逻辑分析,

通过这张图片,我们基本确定了发送短信验证码的基本逻辑,并且在业务逻辑中,我们不能让短信验证码任务阻塞了响应结果,所以我们需要采用celery方式进行异步发送短信验证码且不会阻塞响应。

容联云通讯网址:https://www.yuntongxun.com/

既然确定了,核心逻辑和解决方案,那么接下来我们就进行代码实现了。

1.模板短信SDK下载

https://www.yuntongxun.com/doc/ready/demo/1_4_1_2.html

2.模板短信SDK使用说明

http://doc.yuntongxun.com/p/5a533e0c3b8496dd00dce08c

1. 定义相关视图

# 编写短信验证码视图
class SmsVerVerifications(View):
    def get(self, request, mobile):
        pass

2. 配置相关路由

url(r'^sms_codes/(?P<mobile>1[3-9]\d{9})/$',views.SmsVerVerifications.as_view(),name='SMS')

3. 创建celery程序

在项目中,创建一个celery包。

注意:

  celery是一个独立程序,他不属于Django程序。

4. 编写celery程序入口

# celery启动文件
from celery import Celery


# 为celery使用django配置文件进行设置
import os
if not os.getenv('DJANGO_SETTINGS_MODULE'):
    os.environ['DJANGO_SETTINGS_MODULE'] = 'meiduo_mall.settings.dev'

# 创建celery实例
celery_app = Celery('meiduo')

# 加载celery配置
celery_app.config_from_object('celery_tasks.config')

# 自动注册celery任务
celery_app.autodiscover_tasks(['celery_tasks.sms_task'])

5. 编写celery程序配置文件

# 指定消息队列的位置
broker_url = "redis://127.0.0.1/10"

注意:

  celery程序遵守的是生产者消费者设计模式,这种设计模式需要一个队列容器来保存任务。

举个例子:

  生产者就相当于LOL官方,

  而这个容器就相当于LOL的道具城,

  消费者就相当于我们玩家,

生产者生产任务,然后放到队列容器中,也就相当于LOL出了个新皮肤,并且上架到了LOL道具城;

消费者从队列容器获取任务并完成任务,就相当于我们玩家发现新出了的皮肤,然后买了这么个过程。

6. 创建celery任务

# 定义任务的文件,文件名必须叫tasks.py
# celery的任务就是函数
from celery_tasks.sms_task.yuntongxun.ccp_sms import sendTemplateSMS
from celery_tasks.sms_task import constants
from celery_tasks.main import celery_app


@celery_app.task(name='ccp_send_sms_code') # name是任务的别名,可以通过name参数自定义任务名字
def ccp_send_sms_code(mobile, sms_code):
    """
    发送短信验证码的异步任务
    :param mobile: 手机号
    :param sms_code: 短信验证码
    :return: None
    """
    sendTemplateSMS(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES // 60], constants.SEND_SMS_TEMPLATE_ID)

注意:

  celery任务的文件名字必须是tasks.py

想要完成发送短信验证码的任务,在调用之前我们还需要配置容联云通讯的配置文件。

找到容联云配置文件,并修改以下配置项。

# 说明:主账号,登陆云通讯网站后,可在"控制台-应用"中看到开发者主账号ACCOUNT SID
_accountSid = '你的账号ACCOUNT SID'

# 说明:主账号Token,登陆云通讯网站后,可在控制台-应用中看到开发者主账号AUTH TOKEN
_accountToken = '你的账号AUTH TOKEN'

# 请使用管理控制台首页的APPID或自己创建应用的APPID
_appId = '你的APPID'

7. 启动celery并且调用celery任务完成,异步发送短信验证码。

# 使用celery完成异步发送短信验证码
ccp_send_sms_code.delay(mobile, sms_code)

注意:

  celery任务必须使用.delay方法调用,否则无法调用celery任务。

整体代码如下:

from . import constants
from meiduo_mall.utils.response_code import RETCODE
from celery_tasks.sms_task.tasks import ccp_send_sms_code

# 创建日志输出器
logger = logging.getLogger('django')

# 编写短信验证码视图
class SmsVerVerifications(View):
    def get(self, request, mobile):
        redis_conn = get_redis_connection('verify_code')

        # 获取手机验证码标记
        send_flag = redis_conn.get('send_flag_%s' % mobile)
        # 判断标记是否存在,存在则发送频繁
        if send_flag:
            return http.JsonResponse({'code':RETCODE.THROTTLINGERR,'errmsg':'验证发送过与频繁'})

        # 接收参数
        image_code_client = request.GET.get('image_code')
        uuid = request.GET.get('uuid')

        # 校验参数
        # 创建redis链接,并提取image_code_server
        # redis_conn = get_redis_connection('verify_code')
        image_code_server = redis_conn.get('img_%s' % uuid)

        # 判断图形验证码是否过期
        if not image_code_server:
            return http.JsonResponse({'code':RETCODE.IMAGECODEERR,'errmsg':'图形验证码失效'})

        # 删除图形验证码
        redis_conn.delete('img_%s' % uuid)

        # 实现核心逻辑
        # 对比图形验证码
        if image_code_client.lower() != image_code_server.decode().lower():
            return http.JsonResponse({'code':RETCODE.IMAGECODEERR,'errmsg':'图形验证码错误'})

        # 生成短信验证码
        sms_code = '%06d' % random.randint(0,1000000)
        logger.info(sms_code)

        # 保存短信验证码并设置有效期
        # redis_conn.setex('sms_%s' % mobile,constants.SMS_CODE_REDIS_EXPIRES,sms_code)

        # 避免重复发送短信验证码,需要设置一个标记,用来标记短信验证码是否重复
        # redis_conn.setex('send_flag_%s' % mobile, constants.SEND_SMS_CODE_INTERVAL,'send_flag')

        # 优化redis数据库操作
        # 创建管道
        pl = redis_conn.pipeline()
        # 将命令添加到管道内
        pl.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
        pl.setex('send_flag_%s' % mobile, constants.SEND_SMS_CODE_INTERVAL, 'send_flag')
        # 执行命令
        pl.execute()

        # 发送短信验证码
        # sendTemplateSMS(mobile,[sms_code,constants.SMS_CODE_REDIS_EXPIRES // 60],constants.SEND_SMS_TEMPLATE_ID)

        # 使用celery完成异步发送短信验证码
        ccp_send_sms_code.delay(mobile, sms_code)

        # 返回相应结果
        return http.JsonResponse({'code':RETCODE.OK,'errmsg':'发送短信验证码成功'})

猜你喜欢

转载自www.cnblogs.com/chao666/p/12187445.html