Python實戰專案6-後端多方式登入介面/手機登入介面

2023-03-03 18:00:55

為開源專案共用程式碼

步驟:
	1先fork開源專案
	2clone下來,修改程式碼,進行提交
	3提交pr,等作者同意

Pycharm 使用Git

右鍵檔案會列出Git命令

登入註冊功能分析

多方式登入介面:使用者名稱/手機號/郵箱 + 密碼都可以登陸

傳送手機驗證碼介面 (藉助於第三方簡訊平臺)

簡訊登入介面

註冊介面

手機號是否存在介面

校驗手機號是否存在
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