我正在尝试使用 Flask 和Flask-登录 http://packages.python.org/Flask-Login在 Flask 应用程序中实现用户身份验证的扩展。目标是从数据库中提取用户帐户信息,然后登录用户,但我遇到了困难;但是,我已将其范围缩小到 Flask-Login 行为的特定部分。
根据Flask-登录文档 http://packages.python.org/Flask-Login/#how-it-works,我需要创建一个 user_loader“回调”函数。这个函数的实际目的和实现让我困惑了几天:
您将需要提供 user_loader 回调。使用这个回调
从会话中存储的用户 ID 重新加载用户对象。它
应该获取用户的 Unicode ID,并返回相应的
用户对象。例如:
@login_manager.user_loader
def load_user(userid):
return User.get(userid)
现在,假设我希望用户在表单中输入名称和密码,检查数据库,然后登录用户。数据库的东西工作正常,对我来说没有问题。
这个“回调”函数想要传递一个用户 ID #,并返回 User 对象(我从数据库加载的内容)。但我真的不明白它应该检查/做什么,因为无论如何用户 ID 都是从同一个地方提取的。我可以“某种程度上”让回调工作,但它看起来很混乱/黑客,并且它会使用浏览器请求的每个资源来访问数据库。我真的不想检查我的数据库以便在每次刷新页面时下载 favicon.ico,但 Flask-login 似乎强制这样做。
如果我不再检查数据库,那么我就无法从此函数返回 User 对象。 User 对象/类是在 Flask 路由中创建的用于登录,因此超出了回调的范围。
我不明白的是如何将 User 对象传递到这个回调函数中,而不必每次都访问数据库。或者,找出如何以更有效的方式做到这一点。我肯定错过了一些基本的东西,但我已经盯着它看了几天了,向它扔了各种函数和方法,但没有任何效果。
这是我的测试代码中的相关片段。用户类:
class UserClass(UserMixin):
def __init__(self, name, id, active=True):
self.name = name
self.id = id
self.active = active
def is_active(self):
return self.active
我创建的用于将用户对象返回到 Flask-Login 的 user_loader 回调函数的函数:
def check_db(userid):
# query database (again), just so we can pass an object to the callback
db_check = users_collection.find_one({ 'userid' : userid })
UserObject = UserClass(db_check['username'], userid, active=True)
if userObject.id == userid:
return UserObject
else:
return None
我不完全理解“回调”(必须返回用户对象,该对象是在从数据库中提取后创建的):
@login_manager.user_loader
def load_user(id):
return check_db(id)
登录路径:
@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST" and "username" in request.form:
username = request.form["username"]
# check MongoDB for the existence of the entered username
db_result = users_collection.find_one({ 'username' : username })
result_id = int(db_result['userid'])
# create User object/instance
User = UserClass(db_result['username'], result_id, active=True)
# if username entered matches database, log user in
if username == db_result['username']:
# log user in,
login_user(User)
return url_for("index"))
else:
flash("Invalid username.")
else:
flash(u"Invalid login.")
return render_template("login.html")
我的代码“有点”有效,我可以登录和退出,但正如我所说,它必须命中数据库以获取所有内容,因为我必须在与其余部分不同的命名空间/范围中向回调函数提供一个 User 对象发生登录操作。我很确定我做错了,但我不知道怎么做。
Flask-login 提供的示例代码这样做 https://github.com/maxcountryman/flask-login/blob/master/example/login-example.py,但这只是有效的,因为它是从全局硬编码字典中提取 User 对象,而不是像在数据库这样的现实场景中,必须检查 DB 并创建 User 对象after用户输入他们的登录凭据。我似乎找不到任何其他示例代码来说明使用烧瓶登录数据库。
这里缺少什么?