web專案024-----賬戶登陸

zaaaacki發表於2020-11-30

賬戶登陸

image.png

我們在我們的passport中寫入使用者登陸的程式碼

這裡就是我們要接受的資訊

# 接受引數
    request_dict = request.get_json()
    mobile = request_dict.get('mobile')
    password = request_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,errmag='手機號格式錯誤')

業務邏輯

從資料庫中查詢手機號是否存在

# 業務邏輯處理
    # 從資料庫中查詢手機號是否存在
    try:
        User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        logging.error(e)
        return jsonify(errno=RET.DBERR,errmag='獲取使用者資訊失敗')

接下來,如果手機號存在,驗證密碼

我們需要定義一個驗證密碼的方法在我們的models模型中

我們在模型中定義方法,直接呼叫這個驗證密碼的方法

接下來驗證密碼,儲存登陸狀態,然後返回

# 如果存在,驗證密碼,加not做一個取反
    if user is None or not user.check_pwd_hash(password):
        return jsonify(errno=RET.DATAERR,errmag='賬號密碼不匹配')
    # 如果密碼正確,儲存登陸狀態
    session['name'] = user.name
    session['mobile'] = user.mobile
    session['user_id'] = user.id

    # 返回
    return jsonify(errno=RET.OK,errmag='登陸成功')

然後進入網址,輸入之前註冊的賬號密碼,登陸成功

接下來我們看看我們的程式碼有沒有可以優化的地方

我們可以發現我們如果密碼不正確,就可以一直試,直到密碼正確

我們應該加上限制,如果同一個ip密碼登陸錯誤幾次之後,就一定時間內不能再登陸了

判斷錯誤次數是否超限制,如果超過限制直接返回

我們只定義了怎麼查詢,接下來我們該向redis中新增使用者的查詢次數了

我們應該在驗證密碼那一步進行新增

這裡我們使用了incr這個命令,如果後面的key沒有值,則會預設傳入1,如果再次呼叫這個命令,這個key會在原有的基礎上加1

expirt命令是指定key的過期時間

我們在網站中試一下

到現在我們的登陸介面就搞完了

rt User
from lghome import db
from sqlalchemy.exc import IntegrityError
from lghome import constans

@api.route("/users", methods =["POST"])
def register():
    """
    註冊
    :param: 手機號 簡訊驗證碼 密碼 確認密碼
    :return: json
    """
    # 接受引數,從前端
    request_dict = request.get_json()
    # print(request_dict) # 證明輸出的是字典
    mobile = request_dict.get("mobile")
    sms_code = request_dict.get("sms_code")
    password = request_dict.get("password")
    password2 = request_dict.get("password2")

    # 驗證
    if not all([mobile,sms_code,password,password2]):
        return jsonify(errno=RET.PARAMERR,errms='引數不完整')

    # 判斷手機號格式
    if not re.match(r'1[345678]\d{9}',mobile):
        return jsonify(errno=RET.PARAMERR,errms='手機號格式錯誤')

    if password != password2:
        return jsonify(errno=RET.PARAMERR,errms='兩次密碼不一致')

    # 業務邏輯
    # 從redis取簡訊驗證碼
    try:
        real_sms_code = redis_store.get("sms_code_%s" % mobile)
    except Exception as e:
        logging.error(e)
        return jsonify(errno=RET.DBERR,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:
        logging.error(e)

    # 判斷使用者填寫的驗證碼的正確性
    real_sms_code = real_sms_code.decode() # 轉碼,轉換成字串
    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:
    #     logging.error(e)
    # else:
    #     if user is not None:
    #         # 表示手機好已經被註冊過
    #         return jsonify(errno=RET.DATAERR,errmsg='手機號已經存在')

    # 儲存資料
    user = User(name=mobile,mobile=mobile)  # 密碼需要加密所以先不寫密碼
    # 加密密碼
    user.password = password  # password_hash = generate_password_hash(password)
    # user(name=mobile,mobile=mobile,password_hash='加密之後的密碼')
    try:
        db.session.add(user)
        db.session.commit()
    except IntegrityError as e:
        db.session.rollback()
        logging.error(e)
        return jsonify(errno=RET.DATAEXIST, errmsg='手機號已經存在')
    except Exception as e:
        # 回滾
        db.session.rollback()
        logging.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,errmsg='註冊成功')


@api.route('/sessions', methods =["POST"])
def login():
    """
    使用者登陸
    :param: 手機號,密碼
    :return: json
    """
    # 接受引數
    request_dict = request.get_json()
    mobile = request_dict.get('mobile')
    password = request_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,errms='手機號格式錯誤')
    # 業務邏輯處理
    # 判斷錯誤次數是否超限制,如果超過限制直接返回
    # redis 使用者ip地址:次數
    user_ip = request.remote_addr
    try:
        # bytes
        access_nums = redis_store.get("access_nums_%s" % user_ip)
    except Exception as e:
        logging.error(e)
    else:
        # 判斷次數,從redis中取出來的是一個位元組,不能和整數比
        if access_nums is not None and int(access_nums) >= constans.LOGIN_ERROR_MAX_TIMES:
            return jsonify(errno=RET.REQERR,errmsg='錯誤次數太多,請稍後重試')


    # 從資料庫中查詢手機號是否存在
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        logging.error(e)
        return jsonify(errno=RET.DBERR,errmsg='獲取使用者資訊失敗')
    # 如果存在,驗證密碼,加not做一個取反
    if user is None or not user.check_pwd_hash(password):
        try:
            redis_store.incr("access_nums_%s" % user_ip)
            redis_store.expire("access_nums_%s" % user_ip,constans.LOGIN_ERROR_FORBID_TIME)  # 設定過期時間
        except Exception as e:
            logging.error(e)

        return jsonify(errno=RET.DATAERR,errmsg='賬號密碼不匹配')
    # 如果密碼正確,儲存登陸狀態
    session['name'] = user.name
    session['mobile'] = user.mobile
    session['user_id'] = user.id

    # 返回
    return jsonify(errno=RET.OK,errmsg='登陸成功')

 

 

 

 

 

相關文章