愛租家專案註冊開發流程
註冊————續上篇
一、定義註冊的路由
-
新建passport.py 檔案,註冊到藍圖的檢視
-
定義路由函式的引數——手機號、驗證碼、密碼,密碼2
-
路由的返回引數格式—json
-
整體邏輯
-
校驗引數
-
判斷手機號格式
-
判斷密碼是否一致
-
從redis 取出簡訊驗證碼
-
判斷驗證碼是否過期
-
刪除redis簡訊驗證碼,防止重複使用
-
比較簡訊驗證碼是否正確
-
判斷手機號是否註冊過(因為db資料庫手機號唯一,所以可以直接看儲存到資料庫是否重複來判斷是否註冊)
-
儲存使用者到資料庫(用 類. 屬性 的方法設定值)
-
儲存登陸狀態
-
返回結果
# 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 資料
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);彈出提示框 } } }) }); })