Flask project 1 actual combat: 3. User login (to be improved)

Insert picture description here

(According to the content of teacher's live broadcast)

One, user login

1. Logical analysis of user name login

Insert picture description here

2. Username login interface design

2.1 Request method

Options Program
Request method POST
Request address /sessions

2.2 Request parameters: form

parameter name Types of Must pass Description
mobile string Yes phone number
password string Yes password

2.3 Response result: HTML

Field Description
Login failed Respond to error prompts
login successful Redirect to homepage

3. Username login interface definition

  • Receive parameters
  • Verification parameters
    • Determine whether the parameter is available
    • Is the format of the phone number correct?
  • Judge business logic processing
    • Check whether the mobile phone number exists from the database
    • verify password
  • Save state
  • return
# lghome/api_1_0/passport.py
@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')

    print(mobile,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='手机号格式错误')

    # 判断业务逻辑处理
    # 从数据库查询手机号是否存在
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        logging.error(e)
        return jsonify(errno=RET.DBERR, errmsg='获取信息失败')

	# 验证密码
    if user is None or not user.check_pwd_hash(password):
        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='登录成功')

4. Algorithm optimization

4.1 Limit the number of errors

  • If the number of errors is not limited, the account password will be maliciously tested
  • Limit the number of errors within a certain period of time, after exceeding the limit, login is not allowed
    • After receiving the parameters, first determine whether the front-end IP is out of limit
      • Get the number of times that the IP has been accessed incorrectly from redis
      • When the number of errors is not empty and is greater than or equal to the limit, an error will be returned directly
    • Determine whether the mobile phone number exists (whether it is a registered user) and whether the password is incorrect,
      • If there is an error, the number of errors is increased by 1 and stored in redis, plus the effective time
    # 判断业务逻辑处理
    # 判断错误次数是否超过限制,如果超过限制直接返回
    # redis 用户IP地址:次数
    user_ip = request.remote_addr
    print(user_ip)
    try:
        access_nums=redis_store.get("access_nums_%s"%user_ip)
        print("access_nums_%s"%user_ip,access_nums)
    except Exception as e:
        logging.error(e)
    else:
        if  access_nums is not None and int(access_nums)>=constants.LOGIN_ERROR_MAX_TIMES:
            return jsonify(errno=RET.REQERR, errmsg='错误次数太多,请稍后重试')

    # 验证密码
    # if user is None or not user.check_pwd_hash(password):
    #     return jsonify(errno=RET.DATAERR, errmsg='帐号密码不匹配')
    if user is None or not user.check_pwd_hash(password):
        try:
            redis_store.incr("access_nums_%s" % user_ip)
            redis_store.repire("access_nums_%s"%user_ip,constants.LOGIN_ERROR_FORBID_TIME)
        except Exception as e:
            logging.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='帐号密码不匹配')

4.2 Use pipeline when saving error times

    # 验证密码
    # if user is None or not user.check_pwd_hash(password):
    #     return jsonify(errno=RET.DATAERR, errmsg='帐号密码不匹配')
    if user is None or not user.check_pwd_hash(password):
        try:
            # redis管道
            pl = redis_store.pipeline()
            pl.incr("access_nums_%s" % user_ip)
            pl.repire("access_nums_%s"%user_ip,constants.LOGIN_ERROR_FORBID_TIME)
            pl.execute()
        except Exception as e:
            logging.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='帐号密码不匹配')

Two, check login

  • After the user logs in, when the page is refreshed, the login status needs to be judged
  • Some pages can only be used in the login state, and the login state needs to be judged

1. Interface design

1.1 Request method

Options Program
Request method GET
Request address /sessions

1.2 Request parameters: none

1.3 Response result: json

first name Types of Do you have to Description
errno String Yes error code
errmsg String Yes Error content
data dictionary no {"Name": Login name}

2. Login check interface definition

  • Read session user information
  • If it exists, it means the user is logged in, otherwise it is not logged in
  • Return the corresponding result
def check_login():
    """
    检查登录状态
    :return: 用户的信息或者返回错误信息
    """
    name = session.get('name')
    if name is not None:
        return jsonify(errno=RET.OK, errmsg='true', data={
    
    "name": name})
    else:
        return jsonify(errno=RET.SESSIONERR, errmsg='false')

Three, log out

1. Interface design

1.1 Request method

Options Program
Request method DELETE
Request address /sessions

1.2 Request parameters: none

1.3 Response result: HTML

Field Description
Sign out successfully Redirect to homepage

2. Login check interface definition

  • Clear session information
  • Return the corresponding result
def logout():
    """退出登录"""
    # 清空session
    session.clear()
    return jsonify(errno=RET.OK, errmsg='OK')

Guess you like

Origin blog.csdn.net/laoluobo76/article/details/110558201