1. Logic analysis of SMS verification code
- Key points of knowledge:
- Saving SMS verification code is to prepare for registration.
- In order to avoid malicious testing by users using graphic verification code, the graphic verification code is deleted immediately after the back-end extracts the graphic verification code.
- Django does not have the function of sending SMS, so we use the third-party Ronglian cloud communication SMS platform to help us send SMS verification code.
2. Ronglian cloud communication SMS platform
Objective: to understand the usage of Rong intermodal communication platform and sms SDK
Steps:
- Understanding of ronglianyun communication SMS platform
- Ronglianyun communication sms SDK test
- Encapsulate sending SMS singleton class
- Problem: if multiple SMS verification codes are sent at the same time, multiple RET SDK objects will be created at the same time, which will consume additional memory space
- Solution:
- Singleton design pattern
- Features: a singleton class has only one instance
- Usage scenario: when there is only one instance of a class in the whole system, the singleton design pattern can be used
- Singleton design pattern
-
Introduction to Ronglian cloud communication SMS platform
-
Rong Lianyun official website
- Ronglian cloud communication website: Link address
- Register and log in
-
Ronglian cloud management console
Developer master account:- ACCOUNT SID: unique identification of the account
- AUTH TOKEN: authentication password, equivalent to password
- Rest URL (production): the request address when docking with the platform (online use, non Development)
- Appid (default): assigned when applying for sub applications,
-
Ronglian cloud creation application
-
Apply for online application and conduct qualification certification
-
The qualification certification is completed and the application is successfully launched
-
Add test number
-
SMS template
-
-
Ronglian cloud communication sms SDK test
-
Integrated template sms SDK
- CCPRestSDK.py: the official SDK file written by the developer of Ronglian cloud communication, including the method of sending template SMS
- ccp_sms.py: call the method of sending template SMS
-
Template sms SDK test
- ccp_sms.py file
# -*- coding:utf-8 -*- from verifications.libs.yuntongxun.CCPRestSDK import REST # Note: after logging in to the cloud communication website, you can see the developer's main account ACCOUNT SID in "console - Application" _accountSid = 'ACCOUNT SID' # Note: after logging in to the cloud communication website, you can see the developer's main account AUTH TOKEN in the console - application _accountToken = 'AUTH TOKEN' # Please use the APPID on the homepage of the management console or create your own APPID _appId = 'APPID' # Note: the request address is configured as app.cloopen.com in the production environment _serverIP = 'app.cloopen.com' # Description: request port, production environment is 8883 _serverPort = "8883" # Note: the REST API version number remains unchanged _softVersion = '2013-12-26' # Example of sending SMS code officially provided by cloud communication # Send template SMS # @param to mobile number # @The format of param data content data is array, for example: {'12', '34'}. If replacement is not required, please fill in '' # @param $tempId template Id def sendTemplateSMS(to, datas, tempId): # Initialize REST SDK rest = REST(_serverIP, _serverPort, _softVersion) rest.setAccount(_accountSid, _accountToken) rest.setAppId(_appId) result = rest.sendTemplateSMS(to, datas, tempId) print(result) for k, v in result.items(): if k == 'templateSMS': for k, s in v.items(): print('%s:%s' % (k, s)) else: print('%s:%s' % (k, v)) if __name__ == '__main__': # Note: the SMS template number of the test is 1 sendTemplateSMS('17600992168', ['123456', 5], 1)
- ccp_sms.py file
-
Description of returned results of template sms SDK
{ 'statusCode': '000000', // Status code. " 000000 'means success, otherwise, it means failure 'templateSMS': { 'smsMessageSid': 'b5768b09e5bc4a369ed35c444c13a1eb', // SMS unique identifier 'dateCreated': '20190125185207' // SMS sending time } }
-
Encapsulate sending SMS singleton class
-
Encapsulate sending SMS singleton class
class CCP(object): """Singleton class for sending SMS""" def __new__(cls, *args, **kwargs): # Determine whether class attributes exist_ instance,_ Instance is the only object of class CCP, i.e. singleton if not hasattr(CCP, "_instance"): cls._instance = super(CCP, cls).__new__(cls, *args, **kwargs) cls._instance.rest = REST(_serverIP, _serverPort, _softVersion) cls._instance.rest.setAccount(_accountSid, _accountToken) cls._instance.rest.setAppId(_appId) return cls._instance
-
Encapsulation sending SMS singleton method
def send_template_sms(self, to, datas, temp_id): """ Sending template SMS single example method :param to: Registered mobile number :param datas: Template SMS content data, in the format of list, for example:['123456', 5],If no replacement is required, please fill in '' :param temp_id: The template number is provided free of charge by default id Template with 1 :return: Texting results """ result = self.rest.sendTemplateSMS(to, datas, temp_id) if result.get("statusCode") == "000000": # Return 0, indicating that the SMS is sent successfully return 0 else: # Return - 1, indicating that the sending failed return -1
-
Sending template SMS results by test singleton class
if __name__ == '__main__': # Note: the SMS template number of the test is 1 CCP().send_template_sms('17600992168', ['123456', 5], 1)
-
-
Key points of knowledge
- Ronglian cloud communication is only one of the platforms for sending SMS. There are other cloud platforms available, such as Alibaba cloud. The implementation routines are interlinked.
- Encapsulating the class of sending SMS as a single example belongs to a scheme of performance optimization.
3. SMS verification code backend logic
Objective: to complete the back-end logic of sending SMS verification code with the help of Ronglian cloud communication
Steps:
- Design and define back-end interfaces
- Implement backend logic
- Design of SMS verification code interface
- Request mode
option | programme |
---|---|
Request method | GET |
Request address | /sms_codes/(?P1[3-9]\d{9})/ |
2. Request parameters: path parameters and query strings
Parameter name | type | Is it necessary to pass | explain |
---|---|---|---|
mobile | string | yes | cell-phone number |
image_code | string | yes | Graphic verification code |
uuid | string | yes | Unique number |
3. Response result: JSON
field | explain |
---|---|
code | Status code |
errmsg | information |
-
SMS verification code interface definition
class SMSCodeView(View): """SMS verification code""" def get(self, reqeust, mobile): """ :param reqeust: Request object :param mobile: cell-phone number :return: JSON """ pass
-
Back end logic implementation of SMS verification code
class SMSCodeView(View): """SMS verification code""" def get(self, reqeust, mobile): """ :param reqeust: Request object :param mobile: cell-phone number :return: JSON """ # Receive parameters image_code_client = reqeust.GET.get('image_code') uuid = reqeust.GET.get('uuid') # Calibration parameters if not all([image_code_client, uuid]): return http.JsonResponse({'code': RETCODE.NECESSARYPARAMERR, 'errmsg': 'Missing required parameters'}) # Create an object connected to redis redis_conn = get_redis_connection('verify_code') # Extract graphic verification code image_code_server = redis_conn.get('img_%s' % uuid) if image_code_server is None: # The graphic verification code is out of date or does not exist return http.JsonResponse({'code': RETCODE.IMAGECODEERR, 'errmsg': 'Invalid graphic verification code'}) # Delete the graphic verification code to avoid malicious testing of the graphic verification code try: redis_conn.delete('img_%s' % uuid) except Exception as e: logger.error(e) # Comparison graphic verification code image_code_server = image_code_server.decode() # bytes to string if image_code_client.lower() != image_code_server.lower(): # Compare after converting to lowercase return http.JsonResponse({'code': RETCODE.IMAGECODEERR, 'errmsg': 'Error in input graphic verification code'}) # Generate SMS verification code: generate a 6-digit verification code sms_code = '%06d' % random.randint(0, 999999) logger.info(sms_code) # Save SMS verification code redis_conn.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code) # Send SMS verification code CCP().send_template_sms(mobile,[sms_code, constants.SMS_CODE_REDIS_EXPIRES // 60], constants.SEND_SMS_TEMPLATE_ID) # Response results return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'SMS sent successfully'})
4. SMS verification code front-end logic
Purpose: the two-way binding of Vue.js will be used to show the effect of countdown of 60 seconds
Steps:
- axios sends ajax request to get SMS verification code
- Show the countdown of 60 seconds
- SMS verification code user interaction and verification
-
Vue binding SMS verification code interface
-
register.html
<li> <label>SMS verification code:</label> <input type="text" v-model="sms_code" @blur="check_sms_code" name="sms_code" id="msg_code" class="msg_input"> <a @click="send_sms_code" class="get_msg_code">[[ sms_code_tip ]]</a> <span class="error_tip" v-show="error_sms_code">[[ error_sms_code_message ]]</span> </li>
-
register.js
check_sms_code(){ if(this.sms_code.length != 6){ this.error_sms_code_message = 'Please fill in the SMS verification code'; this.error_sms_code = true; } else { this.error_sms_code = false; } },
-
-
axios request SMS verification code
-
Event handling of sending SMS verification code
send_sms_code(){ // Avoid repeated clicks if (this.sending_flag == true) { return; } this.sending_flag = true; // Calibration parameters this.check_mobile(); this.check_image_code(); if (this.error_mobile == true || this.error_image_code == true) { this.sending_flag = false; return; } // Request SMS verification code let url = '/sms_codes/' + this.mobile + '/?image_code=' + this.image_code+'&uuid='+ this.uuid; axios.get(url, { responseType: 'json' }) .then(response => { if (response.data.code == '0') { // Countdown 60 seconds var num = 60; var t = setInterval(() => { if (num == 1) { clearInterval(t); this.sms_code_tip = 'Get SMS verification code'; this.sending_flag = false; } else { num -= 1; // Show countdown information this.sms_code_tip = num + 'second'; } }, 1000, 60) } else { if (response.data.code == '4001') { this.error_image_code_message = response.data.errmsg; this.error_image_code = true; } else { // 4002 this.error_sms_code_message = response.data.errmsg; this.error_sms_code = true; } this.generate_image_code(); this.sending_flag = false; } }) .catch(error => { console.log(error.response); this.sending_flag = false; }) },
-
-
SMS verification code effect display
5. Supplement SMS verification logic during registration
Objective: to improve the SMS verification logic in the registration process
Steps:
- SMS verification backend logic
- Compare whether the SMS verification codes entered by the user and stored in Redis are consistent
- SMS verification function front end logic
-
Supplementary SMS verification back-end logic during registration
-
Received SMS verification code parameters
sms_code_client = request.POST.get('sms_code')
-
Before saving the registration data, compare the SMS verification code
redis_conn = get_redis_connection('verify_code') sms_code_server = redis_conn.get('sms_%s' % mobile) if sms_code_server is None: return render(request, 'register.html', {'sms_code_errmsg':'Invalid SMS verification code'}) if sms_code_client != sms_code_server.decode(): return render(request, 'register.html', {'sms_code_errmsg': 'Error in entering SMS verification code'})
-
-
Supplement SMS verification front-end logic during registration
-
register.html
<li> <label>SMS verification code:</label> <input type="text" v-model="sms_code" @blur="check_sms_code" name="sms_code" id="msg_code" class="msg_input"> <a @click="send_sms_code" class="get_msg_code">[[ sms_code_tip ]]</a> <span v-show="error_sms_code" class="error_tip">[[ error_sms_code_message ]]</span> {% if sms_code_errmsg %} <span class="error_tip">{{ sms_code_errmsg }} </span> {% endif %} </li>
-
6. Avoid sending SMS verification code frequently
Existing problems:
- Although we did a 60 second countdown function on the front-end interface. However, malicious users can bypass the front-end interface and frequently request SMS verification codes from the back-end.
terms of settlement:
- At the back end, the frequency of users requesting SMS verification code should also be limited. Only one request for SMS verification code is allowed within 60 seconds.
- Cache a value in Redis database, and the validity period is set to 60 seconds.
-
Logic analysis of avoiding frequently sending SMS verification code
-
Logic implementation of avoiding frequently sending SMS verification code
-
Extract and verify send_flag
send_flag = redis_conn.get('send_flag_%s' % mobile) if send_flag: return http.JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': 'Sending text messages too often'})
-
Re write send_flag
# Save SMS verification code redis_conn.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code) # Re write send_flag redis_conn.setex('send_flag_%s' % mobile, constants.SEND_SMS_CODE_INTERVAL, 1)
-
Interface rendering frequently sends SMS prompt information
if (response.data.code == '4001') { this.error_image_code_message = response.data.errmsg; this.error_image_code = true; } else { // 4002 this.error_sms_code_message = response.data.errmsg; this.error_sms_code = true; }
-
7.pipeline operation Redis database
Redis C - S architecture:
- TCP service based on client server model and request / response protocol.
- The client sends a query request to the server and listens for the Socket return.
- It is usually in blocking mode, waiting for the server to respond.
- The server processes the command and returns the result to the client.
Existing problems:
- If the Redis server needs to process multiple requests at the same time, coupled with network latency, the server utilization is not high and the efficiency is reduced.
Solution:
- pipeline
-
Introduction to pipeline
-
pipeline
- You can send multiple commands at one time and return the results at one time after execution.
- pipeline reduces the round-trip delay time by reducing the number of communication between the client and Redis.
-
Principle of implementation
- The principle of implementation is queue.
- The Client can send three commands together in one tcp message.
- Server can put the processing results of the three commands into a tcp message for return.
- The queue is first in first out, which ensures the order of data.
-
-
pipeline operation Redis database
-
Implementation steps
- Create Redis pipeline
- Add Redis request to queue
- Execute request
-
code implementation
# Create Redis pipeline pl = redis_conn.pipeline() # Add Redis request to queue pl.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code) pl.setex('send_flag_%s' % mobile, constants.SEND_SMS_CODE_INTERVAL, 1) # Execute request pl.execute()
-
- As mortals, as gods