flask爱家租房项目开发(五)

本文详细介绍了用户登陆系统的实现过程,包括后端与前端代码编写、登陆状态验证及退出功能。后端采用Python Flask框架,通过session记录用户状态,前端利用jQuery进行AJAX请求,实现了手机号与密码的验证。

文档下载地址: https://download.youkuaiyun.com/download/geek_xiong/11538124

目录

 

登陆

登陆的后端代码编写

后端登陆测试

登陆的前端代码编写

登陆前后端测试

验证登陆状态

退出登陆

后端验证登陆状态的装饰器


登陆

登陆的后端代码编写

  • 获取请求数据:手机号和密码(要求json格式)
  • 判断参数完整性
  • 验证手机号的格式
  • 判断登陆错误的次数,超过限制,则返回
  • 从数据库中取出用户的数据
  • 与用户输入的信息进行比较
    • 验证成功:记录登陆状态到session
    • 验证失败:登陆次数加 1
  • 返回结果
# POST 127.0.0.1:5000/sessions

@api.route('/sessions', methods=['POST'])
def login():
    """登陆
    传递参数: 手机号、密码,
    格式为:json
    """
    # 获取参数
    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[34578]\d{9}', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机号格式错误')

    # 判断登陆错误的次数,超过限制,则返回
    user_ip = request.remote_addr  # 获取用户的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, errmsg='登陆失败次数过多,请稍后重试')

    # 从数据库中查询用户手机号对应的对象数据
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, 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(erno=RET.DATAERR, errmsg='手机号或密码错误')

    # 如果验证成功,保存登陆状态至session中
    session['name'] = user.name
    session['mobile'] = user.mobile
    session['user_id'] = user.id

    return jsonify(errno=RET.OK, errmsg='登陆成功')
# constant.py

# 登陆错误尝试次数
LOGIN_ERROR_MAX_TIMES = 5

# 登陆错误限制的时间,单位:秒
LOGIN_ERROR_FORBID_TIME = 600

后端登陆测试

关闭csrf

使用已注册过的手机号“15111111111”和密码“123456”进行登陆,此账号应返回“登陆成功”

测试手机号或密码错误,返回的结果应该是“手机号或密码错误”

看一下redis中的记录

redis中记录已经错误过一次,设置的在规定时间内是5次,第6次应该返回的结果是“登陆失败次数过多,请稍后重试”

登陆的前端代码编写

function getCookie(name) {
    var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
    return r ? r[1] : undefined;
}

$(document).ready(function() {
    $("#mobile").focus(function(){
        $("#mobile-err").hide();
    });
    $("#password").focus(function(){
        $("#password-err").hide();
    });
    $(".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;
        }
        // 将数据放到data中
        var data = {
            mobile: mobile,
            password: passwd
        };
        // 将data转换成json格式
        var jsonData = JSON.stringify(data);
        // 发起ajax请求
        $.ajax({
            url: '/api/v1.0/sessions',
            type: 'post',
            data: jsonData,
            contentType: 'application/json',
            dataType: 'json',
            headers: {
                'X-CSRFToken': getCookie('csrf_token')
            },
            success: function (resp) {
                if (resp.errno == '0') {
                    location.href = 'index.html'
                } else {
                    $("#password-err span").html(resp.errmsg);
                    $("#password-err").show();
                }
            }
            
        });
    });
});

登陆前后端测试

放开csrf

重新启动项目,清除一下浏览器的缓存

1. 输入已经注册的手机号和正确的密码,结果为跳转到主页

2. 输入已经注册的手机号和错误的密码,结果为“手机号或密码错误”

3. 填写为注册的手机号和密码,结果同2

验证登陆状态

登陆成功后会跳转到主页,主页显示用户名的name值

后端代码

@api.route('/session', methods=['GET'])
def check_login():
    """检查登陆状态"""
    # 尝试从session中获取用户的名字
    name = session.get('name')
    # 如果session中的name存在,则表示已经登陆,否则未登录
    if name is None:
        return jsonify(errno=RET.OK, errmsg='true', data={"name": name})
    else:
        return jsonify(errno=RET.SESSIONERR, errmsg='false')

前端主页在一加载的时候就验证是否登陆

$(document).ready(function(){
    // $(".top-bar>.register-login").show();
    // 页面一加载就判断是否已经登陆,如果已经登陆,显示用户名,否则显示登陆注册按钮
    $.get('/api/v1.0/session', function (resp) {
        if (resp.errno == '0') {
            $(".top-bar>.user-info>.user-name").html(resp.data.name);
            $(".top-bar.user-info").show();
        } else {
            $(".top-bar>.register-login").show();
        }
    }, "json");
    
    ...

});

 

退出登陆

点击用户名会进入个人信息页,点击退出,回到主页,显示注册于登录按钮

退出后端代码

@api.route('/session', methods=['DELETE'])
def logout():
    """退出"""
    # 清除session数据
    session.clear()
    return jsonify(errno=RET.OK, errmsg='ok')

退出前端代码

function getCookie(name) {
    var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
    return r ? r[1] : undefined;
}

function logout() {
    $.ajax({
        url: '/api/v1.0/session',
        type: 'delete',
        headers: {
            'X-CSRFToken':  getCookie('csrf_token')
        },
        dataType: 'json',
        success: function (resp) {
            if (resp.errno == '0') {
                location.href = 'index.html';
            }
        }
    });
}

$(document).ready(function(){
});

后端验证登陆状态的装饰器

import functools

from werkzeug.routing import BaseConverter
from flask import session, jsonify, g

from ihome.utils.response_code import RET

# 定义检验登陆状态的装饰器
def login_required(view_func):
    @functools.wraps(view_func)
    def wrapper(*args, **kwargs):
        # 判断用户的登陆状态
        user_id = session.get('user_id')

        # 如果用户是登陆的,执行视图函数
        if user_id is not None:
            g.user_id = user_id
            return view_func(*args, **kwargs)
        else:
            # 未登录,返回未登录的信息
            return jsonify(errno=RET.SESSIONERR, errmsg='用户未登录')

    return wrapper

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秒不可闫M先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值