04 user registration verification

Determine whether the user name registration functions to achieve

analysis

  • Request method: get
  • url定义:/usernames/(?P<username>\w{5,20})/
  • Request Parameters: url path parameter
parameter Types of Whether the tip must be uploaded description
username String Yes The user enters a user name

Determine whether the mobile phone number registration function to achieve

analysis

  • Request Method: GET
  • url definition:/mobiles/(?P<mobile>1[3-9]\d{9})/
  • Request Parameters: url path parameter
parameter Types of Whether the front must pass description
mobile String Yes User input phone number

Achieve back-end code

  • verifications/views.py
from django.shortcuts import render
from django.http import HttpResponse,JsonResponse
from django_redis import get_redis_connection
from utils.captcha.captcha import captcha    #utils/captcha/captcha.py   captcha实例
from apps.verifications import constants
import logging
from utils.json_fun import to_json_data
from django.views import View
from apps.users import models

#导入日志器
logger = logging.getLogger('django')

#图形验证
class ImageCode(View):
    """
    /verifications/image_codes/
    """
    def get(self,request,image_code_id):
        # 见captcha.py的最后一行,即输出的元组
        text,image = captcha.generate_captcha() #图片展示给用户看,text要临时存入数据库
        con_redis = get_redis_connection(alias='verity_codes')  #连接指定的redis库
        img_key = 'img_{}'.format(image_code_id)    #拼接成img_xxx形式
        # con_redis.setex(img_key,300,text)    #暂存300s
        con_redis.setex(img_key,constants.IMAGE_CODE_REDIS_EXPIRES,text)    #常量一般单独放置,尽量不改源代码,方便以后修改维护
        logger.info('Image_code: {}'.format(text))  #后台日志直接打印,方便调试
        return HttpResponse(content=image,content_type='image/jpg')

#用户名验证
# 1.请求方式    不需要修改数据库,只是去数据库查,用GET
# 2.参数  判断用户名是否存在,传递用户名参数  路由传参比较方便  re_path
class CheckUsernameView(View):
    """
    Check whether the user exists
    GET usernames/(?P<username>|w{5,20})/   #用正则,需要满足这样的方式
    """
    def get(self,request,username):
        count = models.Users.objects.filter(username=username).count()  #统计此用户名的个数
        data = {
            'count': count,
            'username': username,
        }
        # return JsonResponse({'data': data})
        return to_json_data(data=data)  #传一个参数,默认传给第一个参数,考虑到位置用关键字传参

#手机号验证
class CheckMobileView(View):
    """
    GET mobiles/(?P<mobile>\w{5,20})/
    """
    def get(self,request,mobile):
        count = models.Users.objects.filter(mobile=mobile).count()
        data = {
            'count': count,
            'mobile': mobile,
        }
        # return JsonResponse({'data': data})
        return to_json_data(data=data)
  • Creating json_fun.py file utils directory in the project root directory for processing json format conversion function
from django.http import JsonResponse
from .res_code import Code

def to_json_data(errno=Code.OK,errmsg='',data=None,kwargs=None):    #data可有可无
    json_dict = {'errno':errno, #状态码
                 'errmsg':errmsg,
                 'data':data}

    #isinstance判断是否是字典  是否存在,是否是字典,是否为空
    if kwargs and isinstance(kwargs,dict) and kwargs.keys():
        json_dict.update(kwargs)    #字典两个合到一起

    if kwargs and isinstance(kwargs,dict) and kwargs.keys():
        json_dict.update(kwargs)

    return JsonResponse(json_dict)
  • Creating res_code.py file in the root directory of the project utils directory for the situation to return to the front end of the back-end execution
#定义好,需要时直接调用
class Code:
    OK = "0"
    DBERR = "4001"
    NODATA = "4002"
    DATAEXIST = "4003"
    DATAERR = "4004"
    METHERR = "4005"
    SMSERROR = "4006"
    SMSFAIL = "4007"
    SESSIONERR = "4101"
    LOGINERR = "4102"
    PARAMERR = "4103"
    USERERR = "4104"
    ROLEERR = "4105"
    PWDERR = "4106"
    SERVERERR = "4500"
    UNKOWNERR = "4501"
error_map = {
    Code.OK: "成功",
    Code.DBERR: "数据库查询错误",
    Code.NODATA: "无数据",
    Code.DATAEXIST: "数据已存在",
    Code.DATAERR: "数据错误",
    Code.METHERR: "方法错误",
    Code.SMSERROR: "发送短信验证码异常",
    Code.SMSFAIL: "发送短信验证码失败",

    Code.SESSIONERR: "用户未登录",
    Code.LOGINERR: "用户登录失败",
    Code.PARAMERR: "参数错误",
    Code.USERERR: "用户不存在或未激活",
    Code.ROLEERR: "用户身份错误",
    Code.PWDERR: "密码错误",

    Code.SERVERERR: "内部错误",
    Code.UNKOWNERR: "未知错误",
}
  • verifications/urls.py
from django.urls import path,re_path
from apps.verifications import views

app_name = 'verifications'

urlpatterns = [
    path('image_codes/<uuid:image_code_id>/',    #判断image_code_id是否是uuid类型,存为uuid类型,使用uuid转换器
         views.ImageCode.as_view(),
         name='image_codes'),
    re_path('usernames/(?P<username>\w{5,20})/',    #对应auth.js里的路径
            views.CheckUsernameView.as_view(),
            name='check_username'),
    re_path('mobiles/(?P<mobile>1[3-9]\d{9})/',
            views.CheckMobileView.as_view(),
            name='check_mobiles'),
]

[3,9] and 3 comprises only 9 represents, [3-9] represents an integer between 3-9, also comprising 3,9

  • Add the code register.html introduced message.js
{% block domready %}
  <script src="{% static 'js/base/message.js' %}"></script>
  <script src="{% static 'js/users/auth.js' %}"></script>
{% endblock %}

Front-end authentication username

  • But also whether a rear end, a front end to prevent skipping reptiles
  • auth.js
$(function () {
  let $username = $('#user_name');  // 选择id为user_name的网页元素,需要定义一个id为user_name
  let $img = $(".form-item .captcha-graph-img img");  // 获取图像标签
  let sImageCodeId = "";  // 定义图像验证码ID值
  let $mobile = $('#mobile');  // 选择id为mobile的网页元素,需要定义一个id为mobile
  let $smsCodeBtn = $('.form-item .sms-captcha');  // 获取短信验证码按钮元素,需要定义一个id为input_smscode
  let $imgCodeText = $('#input_captcha');  // 获取用户输入的图片验证码元素,需要定义一个id为input_captcha

  // 1、图像验证码逻辑
  generateImageCode();  // 生成图像验证码图片
  $img.click(generateImageCode);  // 点击图片验证码生成新的图片验证码图片


  // 2、判断用户名是否注册
  $username.blur(function () {
    fn_check_usrname();
  });

  // 3、判断用户手机号是否注册
  $mobile.blur(function () {
    fn_check_mobile();
  });

  // 4、发送短信逻辑
  $smsCodeBtn.click(function () {
    // 判断手机号是否输入
    if (fn_check_mobile() !== "success") {
      return
    }

    // 判断用户是否输入图片验证码
    let text = $imgCodeText.val();  // 获取用户输入的图片验证码文本
    if (!text) {
        message.showError('请填写验证码!');
        return
    }

    // 判断是否生成的UUID
    if (!sImageCodeId) {
      message.showError('图片UUID为空');
      return
    }

    // 正常获取参数
    let SdataParams = {
      "mobile": $mobile.val(),   // 获取用户输入的手机号
      "text": text,  // 获取用户输入的图片验证码文本
      "image_code_id": sImageCodeId  // 获取图片UUID
    };

    // for test
    // let SdataParams = {
    //   "mobile": "1886608",   // 获取用户输入的手机号
    //   "text": "ha3d",  // 获取用户输入的图片验证码文本
    //   "image_code_id": "680a5a66-d9e5-4c3c-b8ea"  // 获取图片UUID
    // };

    // 向后端发送请求
    $.ajax({
      // 请求地址
      url: "/sms_codes/",
      // 请求方式
      type: "POST",
      data: JSON.stringify(SdataParams),
      // 请求内容的数据类型(前端发给后端的格式)
      contentType: "application/json; charset=utf-8",
      // 响应数据的格式(后端返回给前端的格式)
      dataType: "json",
      async: false	// 关掉异步功能
    })
      .done(function (res) {
        if (res.errno === "0") {
          // 倒计时60秒,60秒后允许用户再次点击发送短信验证码的按钮
           message.showSuccess('短信验证码发送成功');
          let num = 60;
          // 设置一个计时器
          let t = setInterval(function () {
            if (num === 1) {
              // 如果计时器到最后, 清除计时器对象
              clearInterval(t);
              // 将点击获取验证码的按钮展示的文本恢复成原始文本
              $smsCodeBtn.html("获取验证码");
              // // 将点击按钮的onclick事件函数恢复回去
              // $(".get_code").attr("onclick", "sendSMSCode();");
            } else {
              num -= 1;
              // 展示倒计时信息
              $smsCodeBtn.html(num + "秒");
            }
          }, 1000);
        } else {
          message.showError(res.errmsg);
        }
      })
      .fail(function(){
        message.showError(res.errmsg);
      });

  });


  // 生成一个图片验证码的编号,并设置页面中图片验证码img标签的src属性
  function generateImageCode() {
    // 1、生成一个图片验证码随机编号
    sImageCodeId = generateUUID();
    // 2、拼接请求url /image_codes/<uuid:image_code_id>/
    let imageCodeUrl = "/image_codes/" + sImageCodeId + "/";
    // 3、修改验证码图片src地址
    $img.attr('src', imageCodeUrl)

  }

  // 生成图片UUID验证码
  function generateUUID() {
    let d = new Date().getTime();
    if (window.performance && typeof window.performance.now === "function") {
      d += performance.now(); //use high-precision timer if available
    }
    let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
      let r = (d + Math.random() * 16) % 16 | 0;
      d = Math.floor(d / 16);
      return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
    });
    return uuid;
  }

  // 判断用户名是否已经注册
  function fn_check_usrname() {
    let sUsername = $username.val();  // 获取用户名字符串
    if (sUsername === "") {
      message.showError('用户名不能为空!');
      return
    }
    // test()方法 判断字符串中是否匹配到正则表达式内容,返回的是boolean值 ( true / false )
    if (!(/^\w{5,20}$/).test(sUsername)) {
      message.showError('请输入5-20个字符的用户名');
      return
    }

    // 发送ajax请求,去后端查询用户名是否存在
    $.ajax({
      url: '/usernames/' + sUsername + '/',
      type: 'GET',
      dataType: 'json',
    })
      .done(function (res) {
        if (res.data.count !== 0) {
          message.showError(res.data.username + '已注册,请重新输入!')
        } else {
          message.showInfo(res.data.username + '能正常使用!')
        }
      })
      .fail(function () {
        message.showError('服务器超时,请重试!');
      });
  }

  function fn_check_mobile() {
    let sMobile = $mobile.val();  // 获取用户输入的手机号码字符串
    let SreturnValue = "";
    if (sMobile === "") {
      message.showError('手机号不能为空!');
      return
    }
    if (!(/^1[345789]\d{9}$/).test(sMobile)) {
      message.showError('手机号码格式不正确,请重新输入!');
      return
    }

    $.ajax({
      url: '/mobiles/' + sMobile + '/',
      type: 'GET',
      dataType: 'json',
      async: false
    })
      .done(function (res) {
        if (res.data.count !== 0) {
          message.showError(res.data.mobile + '已注册,请重新输入!');
          SreturnValue = ""
        } else {
          SreturnValue = "success";
          message.showSuccess(res.data.mobile + '此手机号能正常使用');
        }
      })
      .fail(function () {
        message.showError('服务器超时,请重试!');
        SreturnValue = ""
      });
    return SreturnValue

  }

  // get cookie using jQuery
  function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
      let cookies = document.cookie.split(';');
      for (let i = 0; i < cookies.length; i++) {
        let cookie = jQuery.trim(cookies[i]);
        // Does this cookie string begin with the name we want?
        if (cookie.substring(0, name.length + 1) === (name + '=')) {
          cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
          break;
        }
      }
    }
    return cookieValue;
  }

  function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
  }

  // Setting the token on the AJAX request
  $.ajaxSetup({
    beforeSend: function (xhr, settings) {
      if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
        xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
      }
    }
  });
});

Guess you like

Origin blog.csdn.net/xiaogeldx/article/details/90183859