愛租家專案登入開發流程
阿新 • • 發佈:2018-11-11
登入
後端邏輯
-
獲取引數
req_dict = request.get_json()
-
校驗引數
if not all([a,b])
-
手機號格式
[user_ip = request.remote_addr # 使用者的ip地址]()
-
判斷錯誤次數是否超過限制
a=redis_store.get("a_%s" % user_ip ) if int(a) >= 5 :XXX
-
從資料庫中根據手機號查詢使用者的資料物件(把和密碼的校驗放到一塊,防止過詳細的提示導致資料洩露)
-
密碼對比驗證
-
驗證相同成功,儲存登陸狀態,在sessions中
-
models.py 中的檢驗密碼的正確性
cheak_password_hash,
儲存時設定次數,- redis 的incr函式連線:redis-py.readthedoces.io/en/latest 和 reidsdoc.com/index.html
驗證失敗記錄錯誤引數 @api.route("/sessions", methods=["POST"]) def login(): """ 登陸: 引數 手機號,密碼 return: """ # 獲取引數 req_dict = request.get_json() mobile = req_dict.get("mobile") password = req_dict.get("password") # 檢驗引數 if not all([mobile, password]): return jsonify(errno=RET.PARAMERR, errmsg="引數不完整") # 判斷手機的格式 if not re.match(r"1[345678]\d{9}", mobile): return jsonify(errno=RET.PARAMERR,errmsg="手機格式錯誤") # 判斷錯誤請求次數是否超過限制,超過限制返回錯誤 # # redis 記錄: "access_num_請求的IP": 次數 user_ip = request.remote_addr # 使用者的ip地址 print(user_ip) try: access_nums = redis_store.get("access_num_%s"% user_ip) except Exception as e: current_app.logger.error(e) else: if access_nums is not None and int(access_nums) >= constants.LOGIN_ERROR_MAX_TIMES: return jsonify(errno=RET.REQERR, essmsg="請求次數過多,請稍後再試") # 從資料庫根據手機號查詢使用者的資料物件 try: user = User.query.filter_by(mobile=mobile).first() except Exception as e: current_app.logger.error(e) return jsonify(error=RET.DATAERR,errmsg="獲取引數失敗") # 從資料庫的密碼和填寫的密碼對比驗證,驗證時要把使用者名稱和密碼一塊驗證 if user is None or not user.check_password(password): # 如果驗證失敗返回錯誤資訊,記錄錯誤次數 try: redis_store.incr("access_num_%s" % user_ip) redis_store.expire("access_num_%s"% user_ip, constants.LOGIN_ERROR_FORBID_TIME) except Exception as e: current_app.logger.error(e) return jsonify(error=RET.DATAERR, errmsg="密碼或者使用者名稱錯誤") # 如果驗證相同成功,儲存登入狀態, 在session中 session["name"] = user.name session["mobile"] = user.mobile session["user_id"] = user.id return jsonify(errno=RET.OK, errmsg="登入成功")
用postman 驗證後端測試
前端編寫
//login.js 應用ajax
var data = { mobile: mobile, password: passwd }; // 將data轉為json字串 var jsonData = JSON.stringify(data); $.ajax({ url:"/api/v1.0/sessions", type:"post", data: jsonData, contentType: "application/json", dataType: "json", headers:{ "X-CSRFToken":getCookie("csrf_token") }, success: function (data) { if (data.errno == "0") { // 登入成功,跳轉到主頁 location.href = "/"; } else { // 其他錯誤資訊,在頁面中展示 $("#password-err span").html(data.errmsg); $("#password-err").show(); } } });
登陸——登出
定義登陸驗證裝飾器
最簡單的裝飾器——《兩層閉包》
定義的驗證登陸狀態的裝飾器
閉包
概念:可以形象的把它理解為一個封閉的包裹,這個包裹就是一個函式,當然還有函式內部對應的邏輯,包裹裡面的東西就是自由變數,自由變數可以在隨著包裹到處遊蕩。
def func(name):
def inner_func(age):
print 'name:', name, 'age:', age
return inner_func
bb = func('the5fire')
bb(26) # >>> name: the5fire age: 26
-
使用閉包
在python中很重要也很常見的一個使用場景就是裝飾器,Python為裝飾器提供了一個很友好的“語法糖”——@,簡言之你在一個函式func上加上@decorator_func, 就相當於decorator_func(func)::
def decorator_func(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@decorator_func # 等價於 decorator_func(func)
def func(name):
print 'my name is', name
在裝飾器的這個例子中,閉包(wrapper)持有了外部的func這個引數,並 且能夠接受外部傳過來的引數,接受過來的引數在原封不動的傳給func,並返回執行結果。
在內層呼叫時加上@functools.wraps(func) 這樣可以改變內層函式的屬性
import functools def login_required(func): @functools.wraps(func) def wrapper(*arg, **kwargs): pass return wrapper @login_required def itcast(): """itcast python""" pass # itcast -> wrapper print(itcast.__name__) # wrapper.__name__ print(itcast.__doc__) # wrapper.__doc__ TIP:不加 @login_required 裝飾前print的結果時itcast()函式的名和說明文件,加上之後就變成wrapper內層函式的名字,但是一般希望改變裝飾函式的屬性結果,所以在內層函式之上 加上 @functools.wraps(func),這樣不會改變裝飾函式的結果