2012-05-22 13 views
24

私はFlaskを使用しようとしており、Flask-Loginという拡張をFlaskアプリケーションでユーザ認証を実装しようとしています。目標は、データベースからユーザーアカウント情報を取得してユーザーにログインすることですが、私は立ち往生しています。しかし、私はFlask-Loginの動作の特定の部分に絞り込んだ。Flaskログインでuser_loaderコールバックを実装する方法

Flask-Login documentationによると、私は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オブジェクト/クラスは、ログインのためのフラスコルートで作成され、コールバックの範囲外です。

私が理解できないことは、毎回データベースにヒットすることなく、このコールバック関数に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 

私はフラスコ-ログインの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") 

私のコード 'kinda'は動作しますが、ログインとログアウトができますが、私は、異なる名前空間/スコープのコールバック関数にUserオブジェクトを提供する必要があるため、残りのログインアクションがどこから行われるかを示します。私はそれがすべて間違っているとはかなり確信していますが、私はどのように把握できません。

フラスコログインdoes it this wayで提供されているサンプルコードですが、これはDBをチェックする必要があるデータベースのような現実のシナリオではなく、グローバルハードコードされた辞書からUserオブジェクトを引き出しているためですの後にというユーザーオブジェクトが作成され、ユーザーはログイン資格情報を入力します。フラスコログインを使ってデータベースを使用することを示す他のサンプルコードも見つからないようです。

ここには何が欠けていますか?

+0

どのように奇妙です。あなたのログイン()はパスワードを確認しない。 – Houman

+2

@hoomanこれはあくまで例です。 –

答えて

16

リクエストごとにDBからユーザオブジェクトをロードする必要があります。その要件の最大の理由は、Flask-Loginが毎回認証トークンをチェックして、その有効性を確実に継続することです。このトークンの計算には、ユーザーオブジェクトに格納されたパラメーターが必要な場合があります。

たとえば、ユーザーに2つの同時セッションがあるとします。そのうちの1人は、ユーザーがパスワードを変更します。その後の要求では、ユーザーは2番目のセッションからログアウトし、アプリケーションを安全にするために新たにログインする必要があります。ユーザーがコンピュータからログアウトするのを忘れているため、セカンドセッションが盗まれた場合を考えてください。パスワードを変更してすぐに状況を修正する必要があります。また、管理者にユーザーを追い出すこともできます。

このような強制ログアウトが発生するには、Cookieに格納されている認証トークンが、1)新しいパスワードが設定されるたびに変更されるパスワードに基づいている必要があります。 2)ビューを実行する前に、DBに格納されているユーザーオブジェクトの最新の既知の属性と照合する必要があります。

+1

その説明をありがとうございます。これまでの私のアプローチや解決策は間違っていたわけではありませんでしたが、私はそれがなぜそのように働いていたかについていくつか誤った仮定をしました。 –

関連する問題