1. 程式人生 > >愛租家專案註冊開發流程

愛租家專案註冊開發流程

註冊————續上篇

一、定義註冊的路由

  • 新建passport.py 檔案,註冊到藍圖的檢視

  • 定義路由函式的引數——手機號、驗證碼、密碼,密碼2

  • 路由的返回引數格式—json

  • 整體邏輯

    1. 校驗引數

    2. 判斷手機號格式

    3. 判斷密碼是否一致

    4. 從redis 取出簡訊驗證碼

    5. 判斷驗證碼是否過期

    6. 刪除redis簡訊驗證碼,防止重複使用

    7. 比較簡訊驗證碼是否正確

    8. 判斷手機號是否註冊過(因為db資料庫手機號唯一,所以可以直接看儲存到資料庫是否重複來判斷是否註冊)

    9. 儲存使用者到資料庫(用 類. 屬性 的方法設定值)

    10. 儲存登陸狀態

    11. 返回結果

      #  passport.py 
      from . import api
      from flask import request, jsonify, current_app, session
      from ihome.utils.response_code import RET
      from ihome import redis_store, db
      from ihome.models import User
      from sqlalchemy.exc import IntegrityError
      from werkzeug.security import generate_password_hash, check_password_hash
      import re
      
      
      @api.route("/users",methods=["POST"])
      def register():
          """"
          註冊:返回json格式
          引數:手機號,驗證碼,密碼,密碼2
          """
          req_dict = request.get_json()
          mobile = req_dict.get("mobile")
          sms_code = req_dict.get("sms_code")
          password = req_dict.get("password")
          password2 = req_dict.get("password2")
      
          # 校驗引數
          if not all([mobile, sms_code, password, password2]):
              return jsonify(errno=RET.PARAMERR, errmsg="引數不完整")
      
          # 判斷手機格式
          if not re.match(r"1[345678]\d{9}", mobile):
              return jsonify(errno=RET.PARAMERR, errmsg="手機號格式錯誤")
          #
          # 判斷密碼是否一致
          if password != password2:
              return jsonify(errno=RET.PARAMERR, errmsg="兩次密碼不一致")
      
          # 從redis 取出簡訊驗證碼
          try:
              real_sms_code = redis_store.get("sms_code_%s" % mobile)
          except Exception as e:
              current_app.logger.error(e)
              return jsonify(errno=RET.DATAERR, errmsg="讀取真實驗證碼異常")
      
          # 驗證碼是否過期
          if real_sms_code is None:
              return jsonify(errno=RET.NODATA, errmsg="簡訊驗證碼過期")
      
          # 刪除redis 簡訊驗證碼,防止重複使用
          try:
              redis_store.delete("sms_code_%s" % mobile)
          except Exception as e:
              current_app.logger.error(e)
      
          # 判斷簡訊驗證碼是否正確
          if real_sms_code != sms_code:
              return jsonify(errno=RET.DATAERR, errmsg="簡訊驗證碼輸入錯誤")
      
          # # 判斷手機號是否註冊過
          # try:
          #     user = User.query.filter_by(mobile=mobile).first()
          # except Exception as e:
          #     current_app.logger.error(e)
          #     return jsonify(errno=RET.DBERR, errmsg="資料庫異常")
          # else:
          #     if user is not None:
          #         return jsonify(errno=RET.DATAEXIST, errmsg="手機號已存在")
      
          # 儲存使用者資訊到資料庫
          user = User(name=mobile,mobile=mobile)
          # # 類.方法  呼叫
          # user.generate_password_hash(password)
          # 類.屬性的方法設定值
          user.password = password
          try:
              db.session.add(user)
              db.session.commit()
          except IntegrityError as e:
              # s資料庫操作異常後回滾
              db.session.rollback()
              # 手機號出現了重複值,手機號已經註冊過
              current_app.logger.error(e)
              return jsonify(errno=RET.DATAEXIST, errmsg="手機號已存在")
          except Exception as e:
              db.session.rollback()
              current_app.logger.error(e)
              return jsonify(errno=RET.DBERR,errmsg="查詢資料庫異常")
      
          # 儲存登陸狀態到session
          session["name"] = mobile
          session["mobile"] = mobile
          session["user_id"] = user.id
      
          # 返回結果
          return jsonify(errno=RET.OK, essmsg="註冊成功")
      
      
      
  • 密碼加密演算法

    呼叫flask 的werkzeug.security 下的generate_password_hash方法

    加密原理: 隨機生成: 鹽值 加密演算法 結果

    password=“12345” + “abc” sha1 abc$ sdjhgjgfjh

    取值:abc + password 的加密演算法

    ​在模型類models.py 下的User類,引入這個方法生成password_hash 值,

    用 裝飾器 @property 會把函式變為屬性,屬性名即為函式名

    #  models.py Class User():
    # 加上property裝飾器,會把函式變為屬性,屬性名即為函式名
    @property
    def password(self):
        """讀取屬性的函式行為"""
        # print(user.password)  # 讀取屬性是被呼叫
        # # 函式返回值會做為屬性值
        # return "xxxxx"
        raise AttributeError("這個屬性只能設定,不能讀取")
    
    @password.setter
    def password(self, value):
        """
        設定屬性 user.password = value
        :param value: 設定屬性的資料 使用者輸入傳入的密碼
        :return:
        """
        self.password_hash = generate_password_hash(value)
    

    連線到呼叫方法 user.password = password

    二、測試後端

    用postman 傳送請求做測試,模仿前端傳送的json 資料

    1539174392283

    TIP: 測試時出現錯誤:csrf 錯誤,而ihome 配置中的CSRFProtect(app)防護機制只是代表後端防護機制開啟,但是前端並沒有傳過來boby請求體中的csrf_token值,所以測試後端時先關閉,連線前端時在開啟然後補充csrf

    ![csrf防護過程](G:\百度網盤\BaiduNetdiskDownload\python課件18\基礎班-就業班課件資料 -1-4位基礎班 5-14就業班\10-web全棧開發階段-愛家租房專案\17-愛家租房專案\第二天\csrf防護過程.png)

    ![開啟csrf防護機制](G:\百度網盤\BaiduNetdiskDownload\python課件18\基礎班-就業班課件資料 -1-4位基礎班 5-14就業班\10-web全棧開發階段-愛家租房專案\17-愛家租房專案\第二天\開啟csrf防護機制.png)

    三、前端編寫和連線後端資料

    前端預設提交的是form 表單,現在為表單的提交補充自定義的函式行為 (提交事件e)

    // register.js
    
    // js讀取cookie的方法,將csrf_token取出,方便後端csrf進行驗證
    function getCookie(name) {
        var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
    
        return r ? r[1] : undefined;
    }
    
    
    $(".form-register").submit(function(e){
            // 阻止瀏覽器對於表單的預設自動提交行為
            e.preventDefault();
    
            var mobile = $("#mobile").val();
            var phoneCode = $("#phonecode").val();
            var passwd = $("#password").val();
            var passwd2 = $("#password2").val();
            if (!mobile) {
                $("#mobile-err span").html("請填寫正確的手機號!");
                $("#mobile-err").show();
                return;
            } 
            if (!phoneCode) {
                $("#phone-code-err span").html("請填寫簡訊驗證碼!");
                $("#phone-code-err").show();
                return;
            }
            if (!passwd) {
                $("#password-err span").html("請填寫密碼!");
                $("#password-err").show();
                return;
            }
            if (passwd != passwd2) {
                $("#password2-err span").html("兩次密碼不一致!");
                $("#password2-err").show();
                return;
            }
    
            // 呼叫ajax向後端傳送註冊請求
            var req_data = {
                mobile: mobile,
                sms_code: phoneCode,
                password: passwd,
                password2: passwd2,
            };
            var req_json = JSON.stringify(req_data);
            $.ajax({
                url: "/api/v1.0/users",
                type: "post",
                data: req_json,
                contentType: "application/json",
                dataType: "json",
                headers: {
                    "X-CSRFToken": getCookie("csrf_token")
                }, // 請求頭,將csrf_token值放到請求中,方便後端csrf進行驗證
                success: function (resp) {
                    if (resp.errno == "0") {
                        // 註冊成功,跳轉到主頁
                        location.href = "/index.html";
                    } else {
                        alert(resp.errmsg);彈出提示框
                    }
                }
            })
    
        });
    })