实现手机注册——使用Python(DRF应用)接通腾讯云短信服务接口

本篇以注册或者登陆的单次单人发送场景为例,使用Python进行短信接口的调试,从而实现DRF应用的用户注册功能,至于群发或者语音等短信的场景,合此类似,本篇不做完整介绍。

一、申请腾讯云签名并创建模板 


 首先在腾讯云服务中找到短信服务,点击开通,填写基本信息,最后生成如下:

其中SDK AppID和App key是在https请求发送是的必要参数。

然后需要创建一个签名,签名相当于是短信服务的标题,提交后大概审核1-2个小时就可以了。我这里申请的是小程序的服务,所以只需要提供小程序的后台截图就可以了。

 要注意的是签名的内容必须和小程序或者公众号的名称一样,不然会审核不通过。

创建成功以后就会显示已通过,并且创建签名的ID

同理再创建短信正文的模板:

 我们可以看到在正文的内容当中,我设置了两个变量{1}和{2},所以在接下来的传参过程中,仅正文内容的传参就需要两个,另外这里要注意正文模板的ID号,待会在发送请求的过程中也是需要的。

 

二、创建并封装Python短信请求文件tengxun.py


首先我们还是在我们的项目中创建一个tengxun.py文件用于封装短信发送的代码。

以我的项目为例,我使用的DRF,将这个文件放在了app目录下的utils文件夹中。

为了方便进行请求,我们使用的是腾讯短信的SDK,对于Python而言,可以直接使用pip安装:

pip install qcloudsms_py

如下图所示安装成功:

对于单条短信的发送有其特定的发送参数,至于其他类型的发送,大家可以参考腾讯官方的SDK文档,托管到了Github上,所以我直接给出Github的地址,下发都是有说明的:

 https://github.com/qcloudsms/qcloudsms_py

如下创建tengxun.py文件:

#!/usr/bin/env python
# encoding: utf-8
'''
@author: ZhonghangAlex
@contact: 715608270@qq.com
@software: pycharm
@file: tengxun.py
@time: 2018/11/28 12:43
@desc:
'''

from qcloudsms_py import SmsSingleSender
from qcloudsms_py.httpclient import HTTPError

class TengXun(object):
    def __init__(self, appkey):
        self.appkey = appkey

    def send_sms(self, code, mobile):
        # 短信应用SDK AppID
        appid = 1400xx3806  # SDK AppID是1400开头

        # 短信应用SDK AppKey
        appkey = self.appkey

        # 需要发送短信的手机号码
        phone_numbers = "{mobile}".format(mobile=mobile)

        # 短信模板ID,需要在短信应用中申请
        template_id = 2393xx  # NOTE: 这里的模板ID`7839`只是一个示例,真实的模板ID需要在短信控制台中申请

        # 签名
        sms_sign = "Enet车联"  # NOTE: 这里的签名"腾讯云"只是一个示例,真实的签名需要在短信控制台中申请,另外签名参数使用的是`签名内容`,而不是`签名ID`

        ssender = SmsSingleSender(appid, appkey)
        params = ["{code}".format(code=code),"3"]  # 当模板没有参数时,`params = []`
        try:
            result = ssender.send_with_param(86, phone_numbers, template_id, params, sign=sms_sign, extend="", ext="")  # 签名参数未提供或者为空时,会使用默认签名发送短信
        except HTTPError as e:
            print(e)
        except Exception as e:
            print(e)
        print(result)
        return result

# 脚本自测
if __name__ == "__main__":
    teng_xun = TengXun("a067bbcc3xx1c4b924xxc04bef7dc926")
    teng_xun.send_sms("2018", "15927093114")


 上面的很多参数,我都使用了xx做了替换,大家在写的过程中填写自己的相关参数就好。

可以看到在代码中我们封装了一个Tengxun类用于接收参数以及进行短信的发送。

代码下方的三行是脚本自测,先实例化,传入appkey,2018是要生产的验证码,15927093114是要发送的手机号。

这个时候直接运行这个文件就可以完成对短信的发送。

可以看到返回的参数:

说明发送成功,此时手机上也接收到了短信: 

如果你仅仅是想使用一个脚本进行短信发送那么就完成了,接下来我会结合DRF的相关操作,实现一个完整的用户注册功能。

 

三、DRF实现用户注册


为了代码的标准化,我们将一些全局的参数放在settings中:

# 手机号码正则表达式
REGEX_MOBILE = "^1[358]\d{9}$|^147\d{8}$|^176\d{8}$"

# 腾讯短信设置
APIKEY = "a067bbcxx1f1c4b924xxc04bef7dc926"

由于注册功能面向的是用户,所以我们就在user这个app中进行实现:

 首先我们要创建短信验证的数据库表,在models.py中编辑如下:

from datetime import datetime

from django.db import models
from django.contrib.auth.models import AbstractUser

# Create your models here.


class VerifyCode(models.Model):
    """
    短信验证
    """
    code = models.CharField(max_length=10, verbose_name="验证码")
    mobile = models.CharField(max_length=11, verbose_name="电话")

    add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间")

    class Meta:
        verbose_name = "短信验证码"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.code

接着在serserializer.py中设置序列化格式,并进行检验:

#!/usr/bin/env python
# encoding: utf-8
'''
@author: ZhonghangAlex
@contact: 715608270@qq.com
@software: pycharm
@file: serializer.py
@time: 2018/11/28 13:15
@desc:
'''
import re
from rest_framework import serializers
from django.contrib.auth import get_user_model
from datetime import datetime
from datetime import timedelta
from .models import VerifyCode

from VueShop.settings import REGEX_MOBILE


User = get_user_model()


class SmsSerializer(serializers.Serializer):
    mobile = serializers.CharField(max_length=11)

    def validate_mobile(self, mobile):
        """
        验证手机号码
        :param data:
        :return:
        """

        # 手机是否注册
        if User.objects.filter(mobile=mobile).count() != 0:
            raise serializers.ValidationError("用户已经存在")

        # 验证手机号码是否合法
        if not re.match(REGEX_MOBILE, mobile):
            raise serializers.ValidationError("手机号码非法")

        # 验证发送频率
        one_min_ago = datetime.now() - timedelta(hours=0, minutes=1, seconds=0)
        if VerifyCode.objects.filter(add_time__gt=one_min_ago, mobile=mobile).count():
            raise serializers.ValidationError("距离上一次发送未超过60s")

        return mobile

接下来就要构建views.py的代码,我们在Tengxun.py文件中封装类TengXun这个类,所以我们可以在view中进行调用,其中用于单条短信发送的class如下(采用CBV方式):

from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
from random import choice
from rest_framework.mixins import CreateModelMixin
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework import status
from VueShop.settings import APIKEY
from .serializer import SmsSerializer
from utils.tengxun import TengXun
from .models import VerifyCode

class SmsCodeViewset(CreateModelMixin, viewsets.GenericViewSet):
    """
    发送短信验证码
    """
    serializer_class = SmsSerializer

    def generate_code(self):
        """
        生成四位数字的验证码
        :return:
        """
        seeds = "1234567890"
        random_str = []
        for i in range(4):
            random_str.append(choice(seeds))
        return "".join(random_str)

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        mobile = serializer.validated_data["mobile"]

        teng_xun = TengXun(APIKEY)

        code = self.generate_code()

        sms_status = teng_xun.send_sms(code=code, mobile=mobile)

        if sms_status["result"] != 0:
            return Response({
                "mobile":sms_status["errmsg"]
            }, status=status.HTTP_400_BAD_REQUEST)
        else:
            code_record = VerifyCode(code=code, mobile=mobile)
            code_record.save()
            return Response({
                "mobile":mobile
            }, status=status.HTTP_201_CREATED)

然后在url配置中加入code配置:

# 配置code的url
router.register(r'code', SmsCodeViewset, base_name="code")

就完成了DRF应用对短信接口的调用,生成了如下的API:

最后要进行的就是注册表单的验证 

在serializer.py中添加类

class UserRegSerializer(serializers.ModelSerializer):
    code = serializers.CharField(required=True, write_only=True, allow_blank=False, max_length=4, min_length=4,label="验证码",
                                 error_messages={
                                     "blank":"请输入验证码",
                                     "required":"请输入验证码",
                                     "max_length":"验证码格式错误",
                                     "min_length":"验证码格式错误"
                                 }, help_text="验证码")
    username = serializers.CharField(required=True, allow_blank=False, label="用户名", validators=[UniqueValidator(queryset=User.objects.all(), message="用户已经存在")])
    password = serializers.CharField(
        write_only=True,
        style={'input_type':'password'},
        label="密码"
    )

    # 二次加密密码,存储数据库时生成不能反解的密码
    def create(self, validated_data):
        user = super(UserRegSerializer, self).create(validated_data=validated_data)
        user.set_password(validated_data["password"])
        user.save()
        return user

    def validate_code(self, code):
        # 为什么不使用get方法
        # 因为使用get方法需要做异常的捕获
        # try:
        #     verify_records = VerifyCode.objects.get(mobile=self.initial_data["userame"], code=code)
        # except VerifyCode.DoesNotExist as e:
        #     return e
        # except VerifyCode.MultipleObjectsReturned as e:
        #     return e
        verify_records = VerifyCode.objects.filter(mobile=self.initial_data["username"]).order_by("-add_time")
        if verify_records:
            last_records = verify_records[0]
            three_min_ago = datetime.now() - timedelta(hours=0, minutes=3, seconds=0)
            if three_min_ago > last_records.add_time:
                raise serializers.ValidationError("验证码过期")

            if last_records.code != code:
                raise serializers.ValidationError("验证码错误")

        else:
            raise serializers.ValidationError("验证码错误")

    def validate(self, attrs):
        attrs["mobile"] = attrs["username"]
        del attrs["code"]
        return attrs

    class Meta:
        model = User
        fields = ("username", "code", "mobile", "password")

在View中添加视图类,并且通过重写create和perform_create实现token定制化,实现注册后自动登录:

class UserViewSet(CreateModelMixin, viewsets.GenericViewSet):
    """
    用户
    """
    serializer_class = UserRegSerializer
    queryset = User.objects.all()

    # 重新定义create函数 实现注册后自动登录 及定制化Token
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = self.perform_create(serializer)

        re_dict = serializer.data
        payload = jwt_payload_handler(user)
        re_dict["token"] = jwt_encode_handler(payload)
        re_dict["name"] = user.name if user.name else user.username

        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def perform_create(self, serializer):
        return serializer.save()

同样在urls.py中进行路由的配置:

# 配置user的url
router.register(r'user', UserViewSet, base_name="users")

 这样以来就完整地实现了通过短信注册的逻辑。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AlexGeek

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值