flask项目1实战:3、用户登录(待完善)

在这里插入图片描述

(根据居然老师直播课内容整理)

一、用户登录

1、用户名登录逻辑分析

在这里插入图片描述

2、用户名登录接口设计

2.1 请求方式

选项 方案
请求方法 POST
请求地址 /sessions

2.2 请求参数:表单

参数名 类型 是否必传 说明
mobile string 手机号
password string 密码

2.3 响应结果:HTML

字段 说明
登录失败 响应错误提示
登录成功 重定向到首页

3、用户名登录接口定义

  • 接收参数
  • 验证参数
    • 判断参数是否有空
    • 手机号格式是否正确
  • 判断业务逻辑处理
    • 从数据库查询手机号是否存在
    • 验证密码
  • 保存状态
  • 返回
# 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、算法优化

4.1 限制错误次数

  • 如果不限制错误次数,会被恶意测试帐号密码
  • 在一定时间内限制错误次数,超过限制次数后不允许登录
    • 接收参数后,首先判断该前端IP防问是否超限
      • 从redis中取出该IP已访问错误次数
      • 错误次数不为空且大于等于限制次数时,直接返回错误
    • 判断手机号是否存在(是否是注册用户)和密码错误是否正确,
      • 如果错误,错误次数加1并存入redis中,加上有效时间
    # 判断业务逻辑处理
    # 判断错误次数是否超过限制,如果超过限制直接返回
    # 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 保存错误次数时,使用管道

    # 验证密码
    # 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='帐号密码不匹配')

二、检查登录

  • 用户登录后,刷新页面时,需要判断登录状态
  • 有些页面只能在登录状态下使用,也需要判断登录状态

1、接口设计

1.1 请求方式

选项 方案
请求方法 GET
请求地址 /sessions

1.2 请求参数:无

1.3 响应结果:json

名字 类型 是否必须 说明
errno 字符串 错误代码
errmsg 字符串 错误内容
data 字典 {“name": 登录名}

2、登录检查接口定义

  • 读取session用户信息
  • 如果存在表示用户登录了,否则没登录
  • 返回相应结果
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')

三、登出

1、接口设计

1.1 请求方式

选项 方案
请求方法 DELETE
请求地址 /sessions

1.2 请求参数:无

1.3 响应结果:HTML

字段 说明
登出成功 重定向到首页

2、登录检查接口定义

  • 清空session信息
  • 返回相应结果
def logout():
    """退出登录"""
    # 清空session
    session.clear()
    return jsonify(errno=RET.OK, errmsg='OK')

猜你喜欢

转载自blog.csdn.net/laoluobo76/article/details/110558201
今日推荐