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

被折叠的 条评论
为什么被折叠?



