登录, 发送验证码接口, 对官方提供的短信SDK进行二次封装

登录

1.设计数据库表 2.根据需求设计接口 3.书写代码完成接口功能

  • 账号(手机号, 用户名, 邮箱)密码登录

    1. 输入账号密码, 向账号密码登录接口发送post请求
    2. 校验通过后签发token
  • 手机号验证码登录

    1. 输入手机号
    2. 点击发送验证码按钮, 向发送验证码接口发送get请求
    3. 输入验证码, 向手机号验证码登录接口发送post请求
    4. 从django缓存中取出验证码进行校验, 校验通过后签发token
    '''
    # ...luffyapiluffyapiappsuserurls.py
    ...
    urlpatterns = [
        ...,
        path('code/login/', views.CodeLoginAPIView.as_view()),  # 手机号 + 验证码登录接口
    ]
    
    
    # ...luffyapiluffyapiappsuserviews.py
    from rest_framework_jwt.views import JSONWebTokenAPIView
    from . import my_serializers
    
    
    class CodeLoginAPIView(JSONWebTokenAPIView):
        serializer_class = my_serializers.CodeLoginSerializer
        
    
    # ...luffyapiluffyapiappsusermy_serializers.py
    ...
    from rest_framework import serializers
    
    
    class CodeLoginSerializer(serializers.Serializer):
        code = serializers.CharField(min_length=6, max_length=6)
        mobile = serializers.CharField(min_length=11, max_length=11)
    
        def validate(self, attrs):
            mobile = attrs.get('mobile')
            code = attrs.get('code')
    
            if not code.isdigit():  # 校验验证码是否为纯数字, 否则直接抛错, 减少缓存io
                raise serializers.ValidationError('验证码不为纯数字')
            cache_code = cache.get(settings.CODE_CACHE_FORMAT % mobile)  # 获取服务器缓存的验证码
            if code != cache_code:
                raise serializers.ValidationError('验证码有误')
    
            try:
                user = models.User.objects.get(mobile=mobile, is_active=True)
            except:
                raise serializers.ValidationError('该手机号尚未注册')
    
            payload = jwt_payload_handler(user)  
    
            token = jwt_encode_handler(payload) 
    
            self.object = {'token': token, 'user': user}  
            
            cache.delete(settings.CODE_CACHE_FORMAT % mobile)  # 手机号 + 验证码登录成功后删除django中缓存的验证码 
    
            return attrs
    '''
    

发送验证码接口

  1. 产生验证码
  2. 将验证码交给腾讯云发送
  3. 阅读腾讯云的短信API文档
  4. 对官方提供的短信SDK进行二次封装
  5. 短信发送成功后将产生的验证码存到django缓存中
'''
# ...luffyapiluffyapiappsuserurls.py
...
urlpatterns = [
    ...
    path('code/send/', views.SendSmsAPIView.as_view()),  # 发送验证码接口
]


# ...luffyapiluffyapiappsuserviews.py
...
from luffyapi.libs.sms_sdk import send_sms
from luffyapi.utils.sms_code import generate_code
from django.core.cache import cache
from django.conf import settings
from rest_framework.response import Response


class SendSmsAPIView(APIView):
    authentication_classes = []
    permission_classes = []

    def get(self, request, *args, **kwargs):  # get请求的处理效率要高于post请求
        mobile = request.query_params.get('mobile')
        if not mobile:
            return Response(data={'code': 1001, 'detail': 'mobile字段必须提供'}, status=400)
        if not re.match(r'^1[3-9][0-9]{9}$', mobile):
            return Response(data={'code': 1002, 'detail': '手机号格式有误'}, status=400)

        code = generate_code()

        res = send_sms([mobile, ], code, settings.CODE_EXP // 60)  # 短信验证码的过期时间以分钟为单位
        if not res:
            return Response(data={'code': 1003, 'detail': '验证码发送失败'}, status=500)

        cache.set(settings.CODE_CACHE_FORMAT % mobile, code, settings.CODE_EXP)  # django缓存的过期时间以秒为单位

        return Response(data={'code': 0, 'msg': '验证码发送成功', })
        
        
# ...luffyapiluffyapiutilssms_code.py
# 产生六位随机数字验证码
def generate_code():
    import random
    lt = []
    for i in range(10):
        lt.append(str(i))
    rand_lt = random.sample(lt, 6)
    code = ''.join(rand_lt)
    return code


# ...luffyapiluffyapisettingsconst_settings.py
...
CODE_CACHE_FORMAT = 'code_cache_%s'  # 验证码缓存key

CODE_EXP = 30000  # 验证码过期时间
'''

对官方提供的短信SDK进行二次封装

'''
# ...luffyapiluffyapilibssms_sdksettings.py
...  # 调用发送验证码方法需要的固定配置


# ...luffyapiluffyapilibssms_sdksingle_send.py
from qcloudsms_py import SmsSingleSender
from .settings import TEMPLATE_ID, SMS_SIGN, APPID, APPKEY
from luffyapi.utils.my_logging import logger


# 发送验证码
def send_sms(phone_num_lt, code, exp):
    try:
        sender = SmsSingleSender(APPID, APPKEY)
        response = sender.send_with_param(86, phone_num_lt[0], TEMPLATE_ID, (code, exp), sign=SMS_SIGN, extend="", ext="")
        # print(response)  # {'result': 0, 'errmsg': 'OK', 'ext': '', 'sid': '8:rIcypgwqRVSqRCVVJ0e20200113', 'fee': 1}

        if response.get('result') != 0:
            logger.error('验证码发送失败, "code": %s, "detail": %s' % (response.get('result'), response.get('errmsg')))
            return False
        return True

    except Exception as e:
        logger.error('代码运行异常, "detail": %s' % e)
        

# ...luffyapiluffyapilibssms_sdk\__init__.py
from .single_send import send_sms  # 面向包封装
'''
原文地址:https://www.cnblogs.com/-406454833/p/12709285.html