我使用Ajax登录,使用Flask-Login扩展。这是我的服务器端代码:
@app.route('/login', methods=["POST"])
def login():
if current_user.is_authenticated:
redirect_url = url_for('index')
return jsonify(loggedIn=True, redirectUrl=redirect_url)
username = request.form.get('username', '').strip()
password = request.form.get('password', '').strip()
user = User.query.filter_by(username=username).first()
if user and util.encrypt_password(password, user.salt) == user.password:
logged_in_user = CurrentUser(user)
login_user(logged_in_user)
redirect_url = url_for('index')
return jsonify(loggedIn=True, redirectUrl=redirect_url)
else:
return jsonify(loggedIn=False, error='Invalid Email/Password')
和我的客户端代码:
(function(){
$login_form = $('#login_form');
//add validation to form
if( $login_form.length ){
$login_form.parsley()
$login_form.submit(function(e) {
var url = $(this).attr('action');
var data = $(this).serialize();
tryLogin(url, data);
return false;
});
}
function tryLogin(url, data){
var $submitBtn = $('#login_form__submit');
//notify user that we are working
$submitBtn.addClass('btn--loading');
$.ajax({
type: 'POST',
url: url,
data: data,
dataType: 'json',
success: function (data) {
if (data.loggedIn) {
mixpanel.track('login_success');
window.location.href = data.redirectUrl || '/';
}
}
});
}
});
不确定是什么问题,我最近开始看到这个问题,并且失败的次数超过50%。如果失败,它只会重定向到新页面,但不存在会话信息。所有内容都托管在同一个域中。
修改
更多信息:即使登录间歇性地工作,后端也会通过登录,前端会收到loggedIn=True
和redirectUrl
。似乎问题是客户端收到会话/ cookie但不确定为什么会出现间歇性问题。
更新
Wholever现在正在读这个。我无法找到一个好的解决方案。但调试并意识到这肯定是因为Chrome中的一些错误来更新Ajax请求中的cookie /会话数据。 我通过使用redis而不是客户端转移到服务器端会话来解决这个问题。这确保了请求始终具有正确的会话信息。
答案 0 :(得分:2)
默认情况下,Flask中的URL路由器仅响应GET
方法。您正在使用POST
方法在AJAX中发出请求。
看起来您的查看功能应该同时处理GET
和POST
(当登录用户访问此网址时,只需重定向到index
页面?)
因此,您必须明确将methods
参数设置为@app.route
,更改此行
@app.route('/login')
为:
@app.route('/login', methods=['GET', 'POST'])
再试一次。
如果不能正常工作,请发表评论,我会不断更新。
答案 1 :(得分:2)
您可以修改代码以使用werkzeug库吗?
除非你的util有check_password方法。在内部,create hash方法可以为每次调用返回相同salt的不同密码哈希值。这解释了间歇性问题,因为有时返回的哈希匹配,有时它不会。我相信这一切都取决于随机函数,它通常与时钟和内部散列算法有关。
Theres不需要使用werkzeug存储密码哈希,因为它存储在哈希本身并已加盐。我自己使用了werkzeug库进行登录,下面的代码应该可以使用。前提是您使用werkzeug提供的generate_password_hash生成密码哈希和存储而不是数据库。 Werkzeug library
您的代码使用werkzeug:
from werkzeug.security import generate_password_hash, \
check_password_hash
@app.route('/login', methods=["POST"])
def login():
if current_user.is_authenticated:
redirect_url = url_for('index')
return jsonify(loggedIn=True, redirectUrl=redirect_url)
username = request.form.get('username', '').strip()
password = request.form.get('password', '').strip()
user = User.query.filter_by(username=username).first()
if user and check_password_hash(user.password, password):
logged_in_user = CurrentUser(user)
login_user(logged_in_user)
redirect_url = url_for('index')
return jsonify(loggedIn=True, redirectUrl=redirect_url)
else:
return jsonify(loggedIn=False, error='Invalid Email/Password')
控制台的一个例子:
>>> from werkzeug.security import generate_password_hash, check_password_hash
>>> password = 'cat'
>>> a = generate_password_hash(password)
>>> b = generate_password_hash(password)
>>> c = generate_password_hash(password)
>>> for i in (a, b, c):
... print i
...
pbkdf2:sha1:1000$NdpMiLKu$7c24f73766856ac94102733ae9bf93c0f79b5e53
pbkdf2:sha1:1000$dh2mj93K$61103a04a1bcb16e95a44ca3615518b12fecafc1
pbkdf2:sha1:1000$wdGPkX4p$9db55c5035e9c71f7e1e14ece6be619bf9fdaccf
>>> for i in (a, b, c):
... print check_password_hash(i, password)
...
True
True
True
>>> print check_password_hash(a, 'dog')
False
答案 2 :(得分:0)
尝试检查它不是与在Ajax请求中使用cookie相关的jQuery错误:https://stackoverflow.com/a/7189502/882187
此外,尝试在短暂超时后进行重定向,以确保它发生在ajax回调处理程序之外。由于JS中的回调,这个问题可能是间歇性的。如果使用'window.location.href'重定向会破坏cookie处理处理程序,那该怎么办?
答案 3 :(得分:0)
我遇到的问题是,如果我通过AJAX发出过帐请求,“烧瓶登录”将无法登录,但是如果我发出GET请求或从表单过帐,则可以使用。原来,我发布到的URL是http://0.0.0.0:8000/ ...而不是http://localhost:8000/ ...。将网址更改为http://localhost:8000/可以解决我的问题。