使用 flask-login 擴充套件

實現授權系統的一種更簡單的方法是使用 flask-login 擴充套件。該專案的網站包含一個詳細而精心編寫的快速入門,本例中提供了較短版本。

大概的概念

該擴充套件公開了一組用於以下的函式:

  • 記錄使用者
  • 記錄使用者
  • 檢查使用者是否登入,並找出哪個使用者

什麼不做,你自己要做什麼:

  • 沒有提供儲存使用者的方法,例如在資料庫中
  • 沒有提供檢查使用者憑據的方法,例如使用者名稱和密碼

下面是一整套工作所需的最小步驟。

我建議將所有與 auth 相關的程式碼放在單獨的模組或包中,例如 auth.py。這樣,你可以單獨建立必要的類,物件或自定義函式

建立一個 LoginManager

擴充套件使用 LoginManager 類,必須在 Flask 應用程式物件上註冊。

from flask_login import LoginManager
login_manager = LoginManager()
login_manager.init_app(app) # app is a Flask object

如前所述,LoginManager 例如可以是單獨檔案或包中的全域性變數。然後可以將其匯入到建立 Flask 物件的檔案中或在應用程式工廠函式中進行初始化。

指定用於載入使用者的回撥

通常會從資料庫載入使用者。回撥必須返回一個物件,該物件表示與提供的 ID 相對應的使用者。如果 ID 無效,則應返回 None

@login_manager.user_loader
def load_user(user_id):
    return User.get(user_id) # Fetch the user from the database

這可以在建立你的 LoginManager 之後直接完成。

代表你的使用者的類

如上所述,user_loader 回撥必須返回代表使用者的物件。這究竟是什麼意思?例如,該物件可以是儲存在資料庫中的使用者物件的包裝器,也可以是資料庫中直接的模型。該物件必須實現以下方法和屬性。這意味著如果回撥返回資料庫模型,則需要確保將所提及的屬性和方法新增到模型中。

  • is_authenticated

    如果使用者已通過身份驗證,則此屬性應返回 True,即他們已提供有效憑據。你需要確保 user_loader 回撥返回的代表你的使用者的物件返回該方法的 True

  • is_active

    如果這是一個活躍使用者,則此屬性應返回 True - 除了經過身份驗證之外,他們還啟用了帳戶,未被暫停,或者你的應用程式拒絕帳戶的任何條件。非活動帳戶可能無法登入。如果你沒有此類機制,請從此方法返回 True

  • is_anonymous

    如果這是匿名使用者,則此屬性應返回 True。這意味著 user_loader 回撥返回的使用者物件應返回 True

  • get_id()

    此方法必須返回唯一標識此使用者的 unicode,並且可用於從 user_loader 回撥載入使用者。請注意,這必須是 unicode - 如果 ID 本身是 int 或其他型別,則需要將其轉換為 unicode。如果 user_loader 回撥從資料庫返回物件,則此方法很可能返回此特定使用者的資料庫 ID。相同的 ID 當然應該導致 user_loader 回撥稍後返回同一個使用者。

如果你想使事情變得更容易為自己(**它實際上是推薦),你可以繼承 UserMixinuser_loader 回撥(大概資料庫模型)返回的物件。你可以在此處檢視預設情況下如何實現這些方法和屬性。

記錄使用者

該擴充套件程式將驗證使用者輸入的使用者名稱和密碼。事實上,如果你使用使用者名稱和密碼組合或其他機制,擴充套件程式並不在意。這是使用使用者名稱和密碼記錄使用者的示例。

@app.route('/login', methods=['GET', 'POST'])
def login():
    # Here we use a class of some kind to represent and validate our
    # client-side form data. For example, WTForms is a library that will
    # handle this for us, and we use a custom LoginForm to validate.
    form = LoginForm()
    if form.validate_on_submit():
        # Login and validate the user.
        # user should be an instance of your `User` class
        login_user(user)

        flask.flash('Logged in successfully.')

        next = flask.request.args.get('next')
        # is_safe_url should check if the url is safe for redirects.
        # See http://flask.pocoo.org/snippets/62/ for an example.
        if not is_safe_url(next):
            return flask.abort(400)

        return flask.redirect(next or flask.url_for('index'))
    return flask.render_template('login.html', form=form)

通常,日誌記錄使用者是通過呼叫 login_user 並將表示前面提到的使用者的物件例項傳遞給它來完成的。如圖所示,這通常發生在從資料庫中檢索使用者並驗證其憑據之後,但是在此示例中,使用者物件只是神奇地出現。

我已登入使用者,現在怎麼辦?

user_loader 回撥返回的物件可以通過多種方式訪問​​。

  • 在模板中:

    擴充套件使用模板上下文處理器以名稱 current_user 自動注入它。要禁用該行為,請在 LoginManager 建構函式中使用自定義處理器集 add_context_processor=False

      {% if current_user.is_authenticated %}
        Hi {{ current_user.name }}!
      {% endif %}
    
  • 在 Python 程式碼中:

    擴充套件提供了一個名為 current_user 的請求繫結物件。

      from flask_login import current_user    
    
      @app.route("/hello")
      def hello():
          # Assuming that there is a name property on your user object
          # returned by the callback
          if current_user.is_authenticated:
              return 'Hello %s!' % current_user.name 
          else:
              return 'You are not logged in!'
    
  • 使用裝飾器快速限制訪問 login_required 裝飾器可用於快速限制訪問。

      from flask_login import login_required
    
      @app.route("/settings")
      @login_required
      def settings():
          pass
    

記錄使用者

使用者可以通過呼叫 logout_user() 登出 。即使使用者沒有登入也似乎是安全的,因此 @login_required 裝飾器很可能被省略。

@app.route("/logout")
@login_required
def logout():
    logout_user()
    return redirect(somewhere)

如果使用者未登入並訪問 current_user 物件會發生什麼?

通過 defult 返回 AnonymousUserMixin

  • is_activeis_authenticatedFalse
  • is_anonymousTrue
  • get_id() 返回 None

要為匿名使用者使用不同的物件,請提供一個可呼叫的(類或工廠函式),為你的 LoginManager 建立匿名使用者:

login_manager.anonymous_user = MyAnonymousUser

接下來是什麼?

以上是對擴充套件的基本介紹。要了解有關配置和其他選項的更多資訊,強烈建議你閱讀官方指南