登录
1.设计数据库表 2.根据需求设计接口 3.书写代码完成接口功能
-
账号(手机号, 用户名, 邮箱)密码登录
- 输入账号密码, 向账号密码登录接口发送post请求
- 校验通过后签发token
-
手机号验证码登录
- 输入手机号
- 点击发送验证码按钮, 向发送验证码接口发送get请求
- 输入验证码, 向手机号验证码登录接口发送post请求
- 从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 '''
发送验证码接口
- 产生验证码
- 将验证码交给腾讯云发送
- 阅读腾讯云的短信API文档
- 对官方提供的短信SDK进行二次封装
- 短信发送成功后将产生的验证码存到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 # 面向包封装
'''