zoukankan      html  css  js  c++  java
  • Flask-爱家租房项目ihome-03-登录

    登录/登出

    后端逻辑编写

    登录与登出都是对session这个资源的修改,因此url的名词资源就可以设置为sessions,编辑ihome/api_1_0/users.py的视图文件

    # ihome/api_1_0/users.py
    from flask import request, jsonify, current_app, session
    
    @api.route('/sessions', methods=['GET', 'POST', 'DELETE'])
    def handle_sessions():
        if request.method == 'POST':
            # 登录
            return login()
        elif request.method == 'DELETE':
            # 登出
            return logout()
        else:
            # 获取当前登录用户
            return get_login_user()
    

    三个请求方式分别对应:登录POST,登出DELETE,获取当前登录用户GET,分别编写对应的三个函数

    # ihome/api_1_0/users.py
    def login():
        """登录"""
        # 接收数据
        post_dict = request.get_json()
        if not post_dict:
            return jsonify(errno=RET.PARAMERR, errmsg='参数不能为空')
        # 提取数据
        phone = post_dict.get('phone')
        password = post_dict.get('password')
    
        # 校验数据
        if not all([phone, password]):
            return jsonify(errno=RET.PARAMERR, errmsg='参数不完整')
    
        # 限制同一手机号一分钟内只能登陆5次
        his_login_key = f'his_login_{phone}'
        try:
            # incr增加记录的次数,若不存在该key则会创建并默认值为1
            count = redis_connect.incr(his_login_key)
            if int(count) > constants.USER_LOGIN_COUNT:
                return jsonify(errno=RET.REQERR, errmsg='一分钟内只能登录5次')
            redis_connect.expire(his_login_key, constants.USER_LOGIN_EXPIRES)
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg='获取登录记录异常')
    
        # 校验是否已经登录过
        if phone in session.values():
            return jsonify(errno=RET.OK)
    
        # 校验手机号是否注册过
        try:
            user = Users.query.filter_by(phone=phone).first()
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg='获取用户信息异常')
        # 将用户名错误和密码错误放在一起返回,不要返回地太细节
        if not user or not user.check_password_hash(password):
            return jsonify(errno=RET.PWDERR, errmsg='用户名或密码不正确')
    
        # 记录登录session
        session['user_id'] = user.id
        session['name'] = user.name
        session['phone'] = phone
    
        return jsonify(errno=RET.OK)
    
    def logout():
        """登出"""
        # 判断是否登录过
        if not session.get('user_id'):
            return jsonify(errno=RET.NODATA, errmsg='用户未登录')
        # 清除session
        session.pop('user_id')
        session.pop('name')
        session.pop('phone')
    
        return jsonify(errno=RET.OK)
    
    def get_login_user():
        """获取登录用户"""
        # 判断是否登录过
        name = session.get('name')
        if name:
            return jsonify(errno=RET.OK, data={'name': name})
        return jsonify(errno=RET.SESSIONERR, errmsg='用户未登录')
    

    前端逻辑编写-登录

    在登录的js文件中添加登录按钮的逻辑,同样不使用form自带的表单提交功能,自定义表单的提交与返回操作

    //login.js
    $(document).ready(function() {
        ......
        $(".form-login").submit(function(e){
            //阻止默认的表单提交行为
            e.preventDefault();
            mobile = $("#mobile").val();
            passwd = $("#password").val();
            if (!mobile) {
                $("#mobile-err span").html("请填写正确的手机号!");
                $("#mobile-err").show();
                return;
            } 
            if (!passwd) {
                $("#password-err span").html("请填写密码!");
                $("#password-err").show();
                return;
            }
            //发送ajax请求
            //js对象数据转换为json格式
            var postData = JSON.stringify({phone:mobile, password:passwd});
            $.ajax({
                url: 'api/v1.0/sessions',
                type: 'post',
                data: postData,
                contentType: 'application/json',
                headers: {'X-CSRFToken': getCookie('csrf_token')},
                dataType: 'json',
                success: function (resp) {
                    if(resp.errno == '0'){
                        //登录成功,跳转到首页
                        location.href='/index.html';
                    }else{
                        //登录失败
                        alert(resp.errmsg);
                    }
                }
            })
        });
    })
    

    登录成功后,进入主页页面,在主页的右上角显示登录的用户名,编辑主页js文件,页面一加载就调用接口查询登录的用户

    //index.js
    $(document).ready(function(){
        //发送ajax获取登录信息
        $.get("/api/v1.0/sessions", function (resp) {
            if (resp.errno == '0'){
                //已登录,显示登录用户名
                $(".user-info>.user-name").html(resp.data.name)
                $(".user-info").show()
            }else{
                //未登录,显示登录注册框
                $(".top-bar>.register-login").show();
            }
        }, "json")
    

    前端逻辑编写-登出

    点击主页的用户名,来到用户信息页面,最下面的'退出'按钮即为登出功能,设置该按钮的点击事件为logout()编辑该界面的js

    //my.js
    function logout() {
        $.ajax({
            url: 'api/v1.0/sessions',
            type: 'delete',
            dataType: 'json',
            headers: {
                'X-CSRFToken': getCookies('csrf_token')
            },
            success: function (resp) {
                if (resp.errno == '0'){
                    location.href='/'
                }else{
                    alert(resp.errmsg)
                }
            }
        })
    }
    

    登录验证装饰器

    有些页面是需要用户登录才能访问的,比如用户信息页面,因此我们需要在这些页面的视图函数上添加登录的验证,这里使用装饰器的方式,在ihome/utils/commons.py文件中添加该登录装饰器

    # ihome/utils/commons.py
    from flask import session, jsonify, g
    from .response_codes import RET
    import functools
    
    def login_required(view_func):
        """登录验证装饰器"""
        @functools.wraps(view_func)
        def wrapper(*args, **kwargs):
            # 判断登录状态
            user_id = session.get('user_id')
            if not user_id:
                # 没有登录
                return jsonify(errno=RET.SESSIONERR, errmsg='用户未登录')
            # 已登录,将user保存在g对象中
            try:
                user = Users.query.get(user_id)
                g.user = user
                print(g.user)
            except Exception as e:
                current_app.logger.error(e)
                return jsonify(errno=RET.DBERR, errmsg='获取用户异常')
            # 执行视图函数
            return view_func(*args, **kwargs)
        return wrapper
    

    注:

    1. 在session中若未获取到登录用户,则返回错误信息,用户未登录,若已登录,则执行下面的被装饰的视图函数

    2. 在装饰器内部添加@functools.wraps(view_func)能使被装饰函数的文件字符串等属性不会改变

    3. 在可以讲获取到的一些信息存在g变量中,这样在视图函数中就不需要重复查找, 这里将当前登录的User对象存在g对象中

  • 相关阅读:
    1113 Integer Set Partition
    1114 Family Property
    1115 Counting Nodes in a BST
    1116 Come on! Let's C
    Maven 常用命令
    Maven 快照
    Maven 插件
    Maven POM
    Maven 中央仓库
    Maven 依赖机制
  • 原文地址:https://www.cnblogs.com/gcxblogs/p/13527723.html
Copyright © 2011-2022 走看看