Login registration page analysis
Interfaces that need to be written for the user section
- Login with user name and password (multiple login methods)
- Obtain mobile phone verification code interface
- Mobile phone number + verification code login
- Registration interface
- Verify whether the interface exists for the mobile phone number
Verify whether the mobile phone number exists
View class
from rest_framework.viewsets import ViewSet from rest_framework.decorators import action from .models import User from luffy01.utils.common_response import APIResponse class MobileView(ViewSet): @action(methods=['GET'], detail=False) def check_mobile(self, request, *args, **kwargs): try: mobile = request.query_params['mobile'] User.objects.get(mobile=mobile) except Exception as e: # If an error is reported, it means that it was not found. raise Exception('Mobile phone number does not exist') return APIResponse(msg='Mobile phone number exists')
Route distribution
from django.urls import path, include urlpatterns = [ path('api/v1/user/', include('luffy01.apps.user.urls')) ]
Routing
from rest_framework.routers import SimpleRouter from .views import MobileView router = SimpleRouter() # 127.0.0.1:8000/api/v1/user/mobile/check_mobile/ ---get request router.register('mobile', MobileView, 'mobile') urlpatterns = [] urlpatterns + = router.urls
Backend multi-mode login interface
Analysis
Front end
Data carried by the front end: {username: username, mobile phone number, email, password: md5 (password)}
When registering: the password is also encrypted with md5 and brought over.
When we log in, the password we bring is md5 encrypted.
?
\dashrightarrow
? The backend verification fails
Backend
- Take it out from request.data
- Verify that the username and password are correct
?
\dashrightarrow
? The logic is written into the sequence class
- Cooperate with serialization class
?
\dashrightarrow
? Write logic in the global hook and issue tokens
- Return to front end
Summary
- When the serialized class is instantiated and the object is obtained,
Code
Serialization class
from rest_framework import serializers import re from .models import User from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler from django.conf import settings class UserLoginSerializer(serializers.Serializer): username = serializers.CharField() password = serializers.CharField() def _get_user(self, attrs): username = attrs.get('username') password = attrs.get('password') if re.match(r'^1[3-9][0-9]{9}$', username): user = User.objects.filter(mobile=username).first() elif re.match(r'[a-zA-Z0-9_-] + @[a-zA-Z0-9_-] + (.[a-zA-Z0-9_-] + ) + $', username): user = User.objects.filter(email=username).first() else: user = User.objects.filter(username=username).first() if user and user.check_password(password): return user else: raise Exception('User password is wrong') def _get_token(self, user): payload = jwt_payload_handler(user) token = jwt_encode_handler(payload) return token def validate(self, attrs): user = self._get_user(attrs) token = self._get_token(user) self.context['username'] = user.username self.context['token'] = token self.context['icon'] = settings.BACKEND_URL + '/media/' + str(user.icon) return attrs
View function
from rest_framework.viewsets import GenericViewSet from rest_framework.decorators import action from luffy01.utils.common_response import APIResponse from .serializer import UserLoginSerializer class UserLoginView(GenericViewSet): serializer_class = UserLoginSerializer @action(methods=['POST'], detail=False) def mul_login(self, request, *args, **kwargs): ser = self.get_serializer(data=request.data) ser.is_valid(raise_exception=True) username = ser.context.get('username') token = ser.context.get('token') icon = ser.context.get('icon') return APIResponse(username=username, token=token, icon=icon)
Send SMS package
Create directory
Create package in libs
tx_sms __init__.py settings.py sms.py
In settings
SECRET_ID='' SECRET_KEY='' APPID='' SIGN_NAME='' TEMPLATE_ID=''
sms.py
# -*- coding: utf-8 -*- from tencentcloud.common import credential from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException #Import the client models of the corresponding product module. from tencentcloud.sms.v20210111 import sms_client, models #Import optional configuration classes from tencentcloud.common.profile.client_profile import ClientProfile from tencentcloud.common.profile.http_profile import HttpProfile import random import settings import json # 1. Generate a fixed-length random verification code (number) def get_code(number=4): code = '' for i in range(number): r = random.randint(0, 9) code + = str(r) return code # 2 Input the mobile phone number and verification, and send SMS function def send_sms(code, mobile): try: # Necessary steps: # Instantiate an authentication object. The input parameters need to be the Tencent Cloud account key pair secretId and secretKey. # The method used here is to read from environment variables, and these two values need to be set in the environment variables first. # You can also write the key pair directly in the code, but be careful not to copy, upload or share the code with others. # To avoid leaking the key pair and endangering the security of your property. # SecretId, SecretKey query: https://console.cloud.tencent.com/cam/capi cred = credential.Credential("settings.SECRET_ID", "settings.SECRET_KEY") # Instantiate an http option, which is optional and can be skipped if there are no special requirements. httpProfile = HttpProfile() # If you need to specify the proxy access interface, you can initialize hp as follows (no need to ignore it directly) # httpProfile = HttpProfile(proxy="http://username:password@proxyIP:proxyport") httpProfile.reqMethod = "POST" # post request (default is post request) httpProfile.reqTimeout = 30 # Request timeout in seconds (default 60 seconds) httpProfile.endpoint = "sms.tencentcloudapi.com" # Specify the access region domain name (default is nearby access) # Optional steps: # Instantiate a client configuration object, you can specify the timeout and other configurations clientProfile = ClientProfile() clientProfile.signMethod = "TC3-HMAC-SHA256" #Specify signature algorithm clientProfile.language = "en-US" clientProfile.httpProfile = httpProfile # Instantiate the client object to request the product (take SMS as an example) # The second parameter is the region information. You can directly fill in the string ap-guangzhou. For the list of supported regions, please refer to https://cloud.tencent.com/document/api/382/52071#.E5.9C.B0.E5. 9F.9F.E5.88.97.E8.A1.A8 client = sms_client.SmsClient(cred, "ap-guangzhou", clientProfile) # Instantiate a request object. Depending on the calling interface and the actual situation, you can further set the request parameters. # You can directly query the SDK source code to determine which attributes of SendSmsRequest can be set. # The attribute may be a basic type or may refer to another data structure # It is recommended to use IDE for development. You can easily jump to the documentation of each interface and data structure. req = models.SendSmsRequest() # Basic type settings: # The SDK uses pointer style to specify parameters. Even for basic types, you need to use pointers to assign parameters. # SDK provides pointer reference encapsulation functions for basic types #Help link: # SMS console: https://console.cloud.tencent.com/smsv2 # Tencent Cloud SMS Assistant: https://cloud.tencent.com/document/product/382/3773#.E6.8A.80.E6.9C.AF.E4.BA.A4.E6.B5.81 # SMS Application ID: SMS SdkAppId is the actual SdkAppId generated after adding the application in [SMS Console], for example, 1400006666 # The application ID can be viewed by going to [SMS Console](https://console.cloud.tencent.com/smsv2/app-manage) req.SmsSdkAppId = "settings.APPID" # SMS signature content: UTF-8 encoding is used, and an approved signature must be filled in # For signature information, you can go to [Domestic SMS](https://console.cloud.tencent.com/smsv2/csms-sign) or [International/Hong Kong, Macao and Taiwan SMS](https://console.cloud.tencent.com/smsv2 /isms-sign) signature management view req.SignName = settings.SIGN_NAME # Template ID: The approved template ID must be filled in # For the template ID, you can go to [Domestic SMS](https://console.cloud.tencent.com/smsv2/csms-template) or [International/Hong Kong, Macao and Taiwan SMS](https://console.cloud.tencent.com/smsv2 /isms-template) body template management view req.TemplateId = settings.TEMPLATE_ID # Template parameters: The number of template parameters needs to be consistent with the number of variables in the template corresponding to TemplateId. If there are no template parameters, set it to empty. req.TemplateParamSet = [code, '1'] # Issue mobile phone numbers, using the E.164 standard, + [country or region code] [mobile phone number] # Example: + 8613711112222, where there is a + sign in front, 86 is the country code, 13711112222 is the mobile phone number, and the maximum number should not exceed 200 mobile phone numbers. req.PhoneNumberSet = [" + 86" + mobile] # User's session content (can be ignored if not necessary): You can carry user-side ID and other contextual information, and the server will return it as is req.SessionContext = "" # SMS code number extension (can be ignored if not required): Not activated by default. If you need to activate it, please contact [Tencent Cloud SMS Assistant] req.ExtendCode = "" # Domestic text messages do not need to fill in this field; international/Hong Kong, Macao and Taiwan text messages have applied for an independent SenderId and need to fill in this field. The public SenderId is used by default and there is no need to fill in this field. Note: If the monthly usage reaches the specified level, you can apply for an independent SenderId. For details, please contact [Tencent Cloud SMS Assistant] (https://cloud.tencent.com/document/product/382/3773#.E6.8A.80 .E6.9C.AF.E4.BA.A4.E6.B5.81). req.SenderId = "" resp = client.SendSms(req) # Output the string return packet in json format print(resp.to_json_string(indent=2)) response_data_dict = json.loads(resp.to_json_string(indent=2)) if response_data_dict.get('SendStatusSet')[0].get('Code') == 'Ok': return True else: # If it fails, you can take out the message---》Normal sending failed return False except Exception as err: # An error occurred during the sending process and failed. return False
In init
from .sms import get_code, send_sms
SMS verification code interface
from rest_framework.viewsets import ViewSet from rest_framework.decorators import action from luffy01.utils.common_response import APIResponse from luffy01.libs.tx_sms import get_code, send_sms as send_sms_mobile from django.core.cache import cache from threading import Thread class MobileView(ViewSet): @action(methods=['POST'], detail=False) def send_sms(self, request, *args, **kwargs): mobile = request.data.get('mobile') code = get_code() # Save the digital verification code in the cache cache.set('cache_mobile_%s' % mobile, code) # Send text messages asynchronously, using multi-threading. There is no way to know whether the text message is successful or not. There is no need to pay attention to whether it is successful or not. t = Thread(target=send_sms_mobile, args=[code, mobile]) t.start() return APIResponse(msg='SMS has been sent')
SMS login interface
Analysis
Data carried by the front end
?
\dashrightarrow
? {mobile:11111,code:8888}
Backend
- Take out the mobile phone number verification code and verify whether the verification code is correct. If it is correct
- issue token
- Return to front end
Code
View class
from rest_framework.viewsets import GenericViewSet from rest_framework.decorators import action from .models import User from luffy01.utils.common_response import APIResponse from .serializer import UserLoginSerializer,SmsLoginSerializer from django.core.cache import cache class UserLoginView(GenericViewSet): serializer_class = UserLoginSerializer def _login(self, request, *args, **kwargs): ser = self.get_serializer(data=request.data) ser.is_valid(raise_exception=True) username = ser.context.get('username') token = ser.context.get('token') icon = ser.context.get('icon') return APIResponse(username=username, token=token, icon=icon) def get_serializer_class(self): if self.action == 'mul_login': return UserLoginSerializer elif self.action == 'sms_login': return SmsLoginSerializer else: return super().get_serializer_class() @action(methods=['POST'], detail=False) def sms_login(self, request, *args, **kwargs): return self._login(request, *args, **kwargs)
Serialization class
from rest_framework import serializers import re from .models import User from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler from django.conf import settings from django.core.cache import cache class LoginSerializer(serializers.Serializer): def _get_user(self, attrs): pass def _get_token(self, user): payload = jwt_payload_handler(user) token = jwt_encode_handler(payload) return token def validate(self, attrs): user = self._get_user(attrs) token = self._get_token(user) self.context['username'] = user.username self.context['token'] = token self.context['icon'] = settings.BACKEND_URL + '/media/' + str(user.icon) return attrs class SmsLoginSerializer(LoginSerializer): mobile = serializers.CharField() code = serializers.CharField() def _get_user(self, attrs): mobile = attrs.get('mobile') code = attrs.get('code') old_code = cache.get('cache_mobile_%s' % mobile) if code == old_code or '8888': user = User.objects.filter(mobile=mobile).first() if user: return user else: raise Exception('Mobile phone number does not exist') else: raise Exception('Verification code error')
SMS registration interface
Analysis
- Front end: carrying data format
- rear end:
- View class: view class
?
\dashrightarrow
? Registration method
- Serialization class
?
\dashrightarrow
? Verify and save (there are many fields in the table and few are transmitted)
?
\dashrightarrow
? Randomly, generated in a certain format
?
\dashrightarrow
?Later modification)
- View class: view class
Code
Serialization class
from rest_framework import serializers from .models import User class UserRegisterSerializer(serializers.ModelSerializer): code = serializers.CharField(max_length=4, min_length=4, write_only=True) class Meta: model=User fields = ['mobile', 'code', 'password'] def validate(self, attrs): mobile = attrs.get('mobile') code = attrs.get('code') old_code = cache.get('cache_mobile_%s' % mobile) if code == old_code or code == '8888': attrs['username'] = mobile attrs.pop('code') return attrs else: raise Exception('Verification code error') def create(self, validated_data): user = User.objects.create_user(**validated_data) return user
View class
from rest_framework.viewsets import GenericViewSet from rest_framework.decorators import action from .models import User from luffy01.utils.common_response import APIResponse from .serializer import UserRegisterSerializer from rest_framework.mixins import CreateModelMixin class UserRegisterView(GenericViewSet, CreateModelMixin): serializer_class = UserRegisterSerializer @action(methods=['POST'], detail=False) def register(self, request, *args, **kwargs): res = super().create(request, *args, **kwargs) return APIResponse(msg='Registration successful')
Routing
Add to
router.register('register', UserRegisterView, 'register')