1. 程式人生 > >愛租家專案登入開發流程

愛租家專案登入開發流程

登入

後端邏輯

  • 獲取引數 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,儲存時設定次數,

    驗證失敗記錄錯誤引數
    @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();
        }
    }
});

登陸——登出

1539570341917

定義登陸驗證裝飾器

最簡單的裝飾器——《兩層閉包》

commons.py

定義的驗證登陸狀態的裝飾器

1539572363861

1539572304474

閉包

概念:可以形象的把它理解為一個封閉的包裹,這個包裹就是一個函式,當然還有函式內部對應的邏輯,包裹裡面的東西就是自由變數,自由變數可以在隨著包裹到處遊蕩。

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),這樣不會改變裝飾函式的結果