我试图使用Flask和Flask-Login扩展实现Flask应用中的用户认证。目标是从数据库中获取用户账户信息并登录用户,但我遇到了困难; 但是,我已经将其缩小到了Flask-Login行为的特定部分。
根据Flask-Login文档,我需要创建一个user_loader“回调”函数。这个函数的实际目的和实现让我感到困惑了几天:
现在,假设我想让用户在表单中输入用户名和密码,检查数据库并登录用户。数据库的部分可以正常工作,对我来说没有问题。You will need to provide a user_loader callback. This callback is used to reload the user object from the user ID stored in the session. It should take the Unicode ID of a user, and return the corresponding user object. For example:
@login_manager.user_loader def load_user(userid): return User.get(userid)
这个“回调”函数希望传递一个用户ID#,并返回用户对象(其内容从数据库中加载)。但我真的不知道它应该检查/执行什么操作,因为用户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")
我的代码“有点”能用,我可以登录和退出,但正如我所说,它必须为绝对所有的事情访问数据库,因为我必须在不同的命名空间/范围中向回调函数提供用户对象,而此处发生了其余的登录动作。我非常确定我做错了一切,但是我无法弄清楚怎么做。
Flask-Login提供的示例代码是通过这种方式实现的,但这仅适用于从全局硬编码字典中提取User对象,而不是像在真实世界的场景中那样从数据库中检查并创建用户对象,即在用户输入登录凭据之后。我似乎找不到其他说明使用数据库与Flask-Login的示例代码。
我漏掉了什么?