爱租家项目登录开发流程

登录

后端逻辑

  • 获取参数 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),这样不会改变装饰函数的结果

猜你喜欢

转载自blog.csdn.net/F_Liberalism/article/details/83956647