Python实战项目6-后端多方式登录接口/手机登录接口

发布时间 2023-03-22 19:13:45作者: dd随风

为开源项目共享代码

步骤:
	1先fork开源项目
	2clone下来,修改代码,进行提交
	3提交pr,等作者同意

Pycharm 使用Git

右键文件会列出Git命令
image.png

登录注册功能分析

多方式登录接口:用户名/手机号/邮箱 + 密码都可以登陆

发送手机验证码接口 (借助于第三方短信平台)

短信登录接口

注册接口

手机号是否存在接口

校验手机号是否存在
user/urls.py

路由层
from django.urls import path, include
from rest_framework.routers import SimpleRouter
from . import views

router = SimpleRouter()
router.register('user',views.UserView,'user')
urlpatterns = [
    path('',include(router.urls)) // 
]
# urlpatterns += router.urls	

user/views.py

from rest_framework.viewsets import ViewSet
from rest_framework.exceptions import APIException
from rest_framework.decorators import action
from utils.response import APIResponse
from .models import UserInfo
class UserView(ViewSet):
    @action(methods=['get'], detail=False)
    def check_mobile(self, request):
        try:
            # 如果布报错就说明手机号存在
            mobile = request.query_params.get('mobile')
            UserInfo.objects.get(mobile=mobile)
            return APIResponse('手机号存在')
        except Exception as e:
            # raise e  也可以直接返抛出异常,就可以被全局异常捕获到
            raise APIException('手机号不存在!')

视图函数模板

from restframework.response import APIresponse
def send_sms(self, request, *args, **kwargs):
        try:
            # 放心大胆写
        except Exception as e:
            raise e
        return APIResponse()

多方式登录接口

使用用户名/手机号/邮箱+密码登录
发送post请求到后端{"username":"xxx","password":"123"}

# 登录逻辑
1取出前端传入的用户名和密码
2通过用户名和密码去数据库查询
3查到了,签发token
4返回前端

将逻辑放入序列化类中..

视图类

  • ser_obj.context >> 序列化类与视图类沟通的桥梁(本质上是个字典)
from rest_framework.viewsets import ViewSet
from .serializer import UserMulLoginSerializer, MobileLoginSerializer
from rest_framework.decorators import action
from utils.response import APIResponse
from .models import UserInfo
class UserView(ViewSet):
    @action(methods=['post'], detail=False, )
    def login(self, request):
        return self.common_login()

        
    def _get_serializer(self, data): # 因为我们有短信登录和多方式登录,可以将序列化类封装到函数中通过判断获取
        # 判断请求方式返回不同的序列化类
        res = self.request.META.get('PATH_INFO')
        #  PATH_INFO 可以拿到请求的路径信息
        if res == '/api/v1/userinfo/user/mobile_login/':
            return MobileLoginSerializer(data=data)
        return UserMulLoginSerializer(data=data)

    def common_login(self):  
        ser_obj = self._get_serializer(data=self.request.data)
        # 执行这句话,会走字段自己的校验,局部钩子,全局钩子
        ser_obj.is_valid(raise_exception=True)
        token = ser_obj.context.get('token')
        # 有了序列化类对象,通过  对象.context 就可以拿到值
        icon = ser_obj.context.get('icon')
        username = ser_obj.context.get('username')
        return APIResponse(token=token, icon=icon, username=username)

序列化类

from rest_framework import serializers
from .models import UserInfo
from utils.common_serializer import Verification


class UserMulLoginSerializer(serializers.ModelSerializer, Verification):
    # 全局钩子中有很多重复代码,我们直接将其封装到 (多方式登录和手机登录都可以使用)
    # utils目录下的common_serializer.py中
    username = serializers.CharField()
    # 由于序列化类校验时会先走字段自己的校验,Mobile字段我们又设置了unique=True属性
    # 所以如果我们请求来到了字段自己的校验就不会通过,我们需要重写该字段

    class Meta:
        model = UserInfo
        fields = ['username', 'password']  

    def validate(self, attrs): 
        attrs = self._validate(attrs)
        return attrs  # 全局钩子必须返回校验后的数据
如果没有通过序列化类的校验,需抛出异常
我们又封装了全局捕获异常,所以就直接抛出即可

utils/common_serializer/Verification

import re
from django.contrib.auth import authenticate
from rest_framework.exceptions import ValidationError,APIException
from django.core.cache import cache
from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler
from user.models import UserInfo
class Verification():
    def _get_token(self, user_obj):
        pay_load = jwt_payload_handler(user_obj)
        token = jwt_encode_handler(pay_load)
        return token
    def _validate(self,attrs):
        user_obj = self._get_user(attrs)
        token = self._get_token(user_obj)
        self.context['token'] = token  # self 是 序列化类对象 所以可以点context传值进去
        self.context['username'] = user_obj.username
        self.context['icon'] = 'http://127.0.0.1:8000/media/' + str(user_obj.icon)
        return attrs
    def _get_user(self, attrs):
        username = attrs.get('username')
        password = attrs.get('password')
        mobile = attrs.get('mobile')
        if mobile:
            if not re.match(r'^1[3-9][0-9]{9}$', mobile):
                raise ValidationError('手机号格式输入错误')
            code = attrs.get('code')
            old_code = cache.get('sms_code_%s' % mobile)
            if code == old_code:
                return UserInfo.objects.filter(mobile=mobile).first()
            raise APIException('验证码错误')
        
        if re.match(r'^1[3-9][0-9]{9}$', username):
            user_obj = UserInfo.objects.filter(mobile=username).first()
            if user_obj.check_password(password) and user_obj:
                return user_obj
            raise ValidationError('用户名或密码错误')
            # user_obj = authenticate(mobile=username, password=password)
        elif re.match(r'^.+@.+$', username):
            user_obj = authenticate(email=username, password=password)
        else:
            user_obj = authenticate(username=username, password=password)
        if not user_obj:
            raise ValidationError('用户名或密码错误')
        return user_obj
            

腾讯云短信申请

  • 发送短信接口,借助于第三方短信平台

我们在使用云短信前需要自己申请Vx公众号(个人的即可)

  • 使用腾讯短信

微信扫码登录

  • 搜索短信:
  • 创建短信签名:公众号注册,提交等待审核
  • 创建短信正文模版
  • 等待审核
  • 发送短信(api接口 SDK)

API: 咱们学习过的API接口,写起来比较麻烦,自己分析接口,对上即可
SDK:集成开发工具包,分语言,java,python,go
使用python 对api进行封装成包
以后我们只需要,安装包,导入包,包名.发送短信,传入参数,就可以发送了
pip install tencentcloud-sdk-python