Flask とFlask-Login拡張機能を使用して、Flask アプリにユーザー認証を実装しようとしています。目標は、データベースからユーザー アカウント情報を取得し、ユーザーをログインさせることですが、行き詰まっています。ただし、Flask-Login 動作の特定の部分に絞り込みました。
Flask-Login のドキュメントによると、user_loader の「コールバック」関数を作成する必要があります。この関数の実際の目的と実装について、数日間混乱していました。
user_loader コールバックを提供する必要があります。このコールバックは、セッションに保存されているユーザー ID からユーザー オブジェクトを再読み込みするために使用されます。ユーザーの Unicode ID を取得し、対応するユーザー オブジェクトを返す必要があります。例えば:
@login_manager.user_loader def load_user(userid): return User.get(userid)
ここで、ユーザーが名前とパスワードをフォームに入力し、データベースと照合して、ユーザーにログインさせたいとします。データベースは問題なく動作し、私にとっては問題ありません。
この「コールバック」関数は、ユーザー ID # を渡され、User オブジェクト (データベースからロードしている内容) を返します。しかし、とにかくユーザーIDはすべて同じ場所から取得されるため、チェック/実行することになっていることを実際には理解できません。私はコールバックを機能させることができますが、それは厄介/ハックのようで、ブラウザが要求するすべてのリソースでデータベースにヒットします。ページを更新するたびに favicon.ico をダウンロードするためにデータベースをチェックしたくありませんが、フラスコログインはこれを強制しているようです。
データベースをもう一度チェックしないと、この関数から User オブジェクトを返す方法がありません。ユーザー オブジェクト/クラスは、ログイン用のフラスコ ルートで作成されるため、コールバックの範囲外になります。
私が理解できないのは、毎回データベースにアクセスすることなく、このコールバック関数に 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 によって提供されるサンプル コードはこのように実行しますが、これはデータベースのような実際のシナリオではなく、ハードコードされたグローバル ディクショナリからユーザー オブジェクトをプルするためにのみ機能します。DB をチェックして、ユーザーがログイン資格情報を入力した後に作成されるユーザー オブジェクト。そして、flask-login でデータベースを使用することを示す他のサンプル コードを見つけることができないようです。
ここで何が欠けていますか?