我对烧瓶和烧瓶登录很新,并且我已经在这几天挣扎了。
我试图像这样记录用户:
from creds import auth_username, auth_password, pgsql_dbuser, pgsql_dbpassword, pgsql_db1name
from flask import Flask, render_template, request, Response, redirect, url_for
from flask.ext.bcrypt import Bcrypt
from flask.ext.login import LoginManager, login_required, login_user, current_user, logout_user
import logging
import psycopg2
import uuid
import datetime
app = Flask(__name__)
app.secret_key = str(uuid.uuid4()) # <- required by login_manager.init_app(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'index'
@app.route('/', methods=['GET','POST'])
def index():
page_name = '/'
if request.method == 'POST':
email = request.form['email']
candidate_password = request.form['password']
user = finduserindbbyemail(email)
if user != None:
password_hash = checkuserpasswordindb(email)
if bcrypt.check_password_hash(password_hash, candidate_password):
user_object = User(user)
result = login_user(user_object) # <- here for successful login
return redirect(url_for('loggedin', user_object=type(user_object), user=user, result=result, current_user=current_user))
else:
user_object = User(user)
error_message = "The password you entered is incorrect"
return render_template('index.html', error_message=error_message)
else:
error_message = "The email address you entered does not match any we have in our records"
return render_template('index.html', error_message=error_message)
if request.method == 'GET':
return render_template('index.html')
我有一个User类和一个用户回调:
class User():
def __init__(self, user):
self.user = user
def is_authenticated(self):
return True
def is_active(self):
return True
def is_anonymous(self):
return False
def get_id(self):
return unicode(self.user)
@login_manager.user_loader
def load_user(user):
con = psycopg2.connect(database=pgsql_db1name, user=pgsql_dbuser, password=pgsql_dbpassword, host='localhost')
uuid = "'"+user+"'"
cur = con.cursor()
cur.execute("SELECT uuid FROM users WHERE uuid = "+ uuid)
uuid = cur.fetchone()
con.close()
if uuid != None:
user = unicode(uuid[0])
return User.get_id(user)
else:
return None
验证成功后(显然?),用户被重定向到一个登录页面,该页面有一个@login_required
装饰器。但是,不是加载登录页面,应用程序将用户重定向到登录页面,告诉我用户没有登录?
如果尝试向页面发送值并删除@login_required
装饰器,以便我可以看到该页面,这就是我在登录后在浏览器中看到的内容&#39;:
current_user.is_authenticated() = False
current_user.is_active() = False
current_user.is_anonymous() = True
current_user.get_id() = None
user_object = <type 'instance'>
user = 2ca1296c-374d-43b4-bb7b-94b8c8fe7e44
login_user = True
current_user = <flask_login.AnonymousUserMixin object at 0x7f2aec80f190> Logout
看起来我的用户还没有被记录并且被视为匿名? 谁能看到我做错了什么?我很难理解这应该如何运作。
答案 0 :(得分:2)
所以..我设法让它工作,但没有使用user_loader回调。无论出于何种原因,我的用户加载器都表现出与此相同的行为: Flask-login with static user always yielding 401- Unauthorized
无论如何,我使用了一个request_loader回调,而不是基于这个例子: http://gouthamanbalaraman.com/blog/minimal-flask-login-example.html
所以对于登录的用户,从这里开始:
if bcrypt.check_password_hash(password_hash, candidate_password):
user_object = User(user, password_hash)
result = login_user(user_object) # <- here for successful login
token = user_object.get_auth_token(user, password_hash)
return redirect(url_for('loggedin', token=token))
我创建了一个用户对象,其中包含用户的id和密码哈希值。 然后我登录用户。然后我使用itsdangerous创建用户ID和密码哈希的时间序列化标记。 get_auth_token函数是User类的一部分。它看起来像这样:
class User():
def __init__(self, user, password_hash):
self.user = user
self.password = password_hash
.
.
.
def get_auth_token(self, user, password):
data = [str(self.user), self.password]
return serializer.dumps(data, salt=serializer_secret)
你需要在代码的开头创建一个序列化器:
serializer = URLSafeTimedSerializer(serializer_secret)
因此,在创建令牌后,将其作为URL查询参数传递给登录视图。 当您尝试加载login_required页面时,例如我的登录页面,这是login_user在成功登录后重定向到的位置,将执行request_loader回调。它看起来像这样:
@login_manager.request_loader
def load_user_from_request(request):
if request.args.get('token'):
token = request.args.get('token')
max_age = 1
try:
data = serializer.loads(token, salt=serializer_secret, max_age=max_age)
username = data[0]
password_hash = data[1]
found_user = finduserindbbyuuid(username)
found_password = checkuserpasswordindbbyuuid(username)
if found_user and found_password == password_hash:
user_object = User(found_user, password_hash)
if (user_object.password == password_hash):
return user_object
else:
return None
else:
return None
except BadSignature, e:
pass
else:
return None
这是我的user_loader失败的地方。我已成功登录,但user_loader始终返回None,因此我的用户将被视为匿名。
因此,对于请求加载器,它会检查请求URL是否包含“令牌”#39;查询字符串中的参数。如果是这样,它需要它的价值并使用它的危险,反序列化数据。 您可以使用定时序列化器使令牌过期,但也有非定时序列化器。令牌反序列化后,取用户和密码哈希并检查数据库是否存在,这与user_loader应该工作的方式完全相同..我想?我的user_loader没有用,所以我很可能做错了。
无论如何,如果用户和密码在数据库中匹配,则返回用户对象和bam,登录工作。
我不确定我是不是以正确的方式做到这一点,因为我的裤子几乎要飞得很好。我看到人们使用token_loader而不是request_loader回调函数加载令牌的示例,但我无法弄清楚如何设置&amp;获取身份验证令牌给&amp;来自客户。也许生病了......有一天......
如果你有同样的问题,也许这可能会有所帮助?或者只是让我知道你的想法
欢呼声
答案 1 :(得分:0)
在您通过登录表单后,可能无法登录用户或current_user的另一个原因是匿名的:在数据库中的用户上设置了active = false标志。在docs中确认了此行为:
flask_login.login_user(用户,记住= False,持续时间=无,强制= False,新鲜= True)[源代码] 登录用户。您应该将实际的用户对象传递给该用户。如果用户的is_active属性为False,则除非强制为True,否则他们将不会登录。
如果登录尝试成功,它将返回True;否则,将返回False(即,由于用户处于非活动状态)。
因此,当您调用login_user时,您可以执行以下操作:
login_user(user, remember=form.remember_me.data, force=True)
,如果要允许不活动的用户登录。
答案 2 :(得分:0)
我在搜索Flask-Login + Flask-Dance的帮助时找到了此页面。我在带有current_user
装饰器的处理程序中看到AnonymousUserMixin
为@login_required
。就我而言,请确保@app.route
在@login_required
上方的行中已解决了该问题。正确的顺序在文档中:https://flask-login.readthedocs.io/en/latest/#flask_login.login_required。