Flask-Login學習筆記

Flask-Login 爲 Flask 提供了用戶會話管理。它處理了日常的登入,登出並且長時間記住用戶的會話。
它會:

  • 在會話中存儲當前活躍的用戶 ID,讓你能夠自由地登入和登出。
  • 讓你限制登入(或者登出)用戶可以訪問的視圖。
  • 處理讓人棘手的 “記住我” 功能。
  • 幫助你保護用戶會話免遭 cookie 被盜的牽連。
  • 可以與以後可能使用的 Flask-Principal 或其它認證擴展集成
    但是,它不會:
  • 限制你使用特定的數據庫或其它存儲方法。如何加載用戶完全由你決定。
  • 限制你使用用戶名和密碼,OpenIDs,或者其它的認證方法。
  • 處理超越 “登入或者登出” 之外的權限。
  • 處理用戶註冊或者賬號恢復。

配置你的應用
對一個使用 Flask-Login 的應用最重要的一部分就是 LoginManager 類。你應該在你的代碼的某處爲應用創建一個,像這樣:

login_manager = LoginManager()

登錄管理(login manager)包含了讓你的應用和 Flask-Login 協同工作的代碼,比如怎樣從一個 ID 加載用戶,當用戶需要登錄的時候跳轉到哪裏等等。

一旦實際的應用對象創建後,你能夠這樣配置它來實現登錄:

from flask_login import LoginManager
from flask import Flask

app = Flask(__name__)
login_manager = LoginManager(app)

它是如何工作
你必須提供一個 user_loader 回調。這個回調用於從會話中存儲的用戶 ID 重新加載用戶對象。它應該接受一個用戶的 unicode ID 作爲參數,並且返回相應的用戶對象。比如:

@login_manager.user_loader
def load_user(userid):
    return User.get(userid)

如果 ID 無效的話,它應該返回 None (而不是拋出異常)。(在這種情況下,ID 會被手動從會話中移除且處理會繼續)

你的用戶類

你用來表示用戶的類需要實現這些屬性和方法:

  1. is_authenticated
    當用戶通過驗證時,也即提供有效證明時返回 True 。(只有通過驗證的用戶會滿足 login_required 的條件。)
  2. is_active
    如果這是一個活動用戶且通過驗證,賬戶也已激活,未被停用,也不符合任何你 的應用拒絕一個賬號的條件,返回 True 。不活動的賬號可能不會登入(當然, 是在沒被強制的情況下)。
  3. is_anonymous
    如果是一個匿名用戶,返回 True 。(真實用戶應返回 False 。)
  4. get_id()
    返回一個能唯一識別用戶的,並能用於從 user_loader 回調中加載用戶的 unicode 。注意着 必須 是一個 unicode —— 如果 ID 原本是 一個 int 或其它類型,你需要把它轉換爲 unicode 。

要簡便地實現用戶類,你可以從 UserMixin 繼承,它提供了對所有這些方法的默認 實現。(雖然這不是必須的。)

Login 示例
一旦用戶通過驗證,你可以使用 login_user 函數讓用戶登錄。例如:

@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')
        # next_is_valid should check if the user has valid
        # permission to access the `next` url
        if not next_is_valid(next):
            return flask.abort(400)

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

警告: 你必須驗證 next 參數的值。如果不驗證的話,你的應用將會受到重定向的攻擊。

就這麼簡單。你可用使用 current_user 代理來訪問登錄的用戶,在每一個模板中都可以使用 current_user:

{% if current_user.is_authenticated() %}
  Hi {{ current_user.name }}!
{% endif %}

需要用戶登入 的視圖可以用 login_required 裝飾器來裝飾:

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

當用戶要登出時:

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

他們會被登出,且他們會話產生的任何 cookie 都會被清理乾淨。

定製登入過程

默認情況下,當未登錄的用戶嘗試訪問一個 login_required 裝飾的視圖,Flask-Login 會閃現一條消息並且重定向到登錄視圖。(如果未設置登錄視圖,它將會以 401 錯誤退出。)

登錄視圖的名稱可以設置成 LoginManager.login_view。例如:

login_manager.login_view = "users.login"

默認的閃現消息是 Please log in to access this page.。要自定義該信息,請設置 LoginManager.login_message:

login_manager.login_message = u"**************."

要自定義消息分類的話,請設置 LoginManager.login_message_category:

login_manager.login_message_category = "info"

當重定向到登入視圖,它的請求字符串中會有一個 next 變量,其值爲用戶之前訪問的頁面。

如果你想要進一步自定義登入過程,請使用 LoginManager.unauthorized_handler 裝飾函數:

@login_manager.unauthorized_handler
def unauthorized():
    # do stuff
    return a_response

使用 Request Loader 定製登錄

有時你想要不使用 cookies 情況下登錄用戶,比如使用 HTTP 頭或者一個作爲查詢參數的 api 密鑰。這種情況下,你應該使用 request_loader 回調。這個回調和 user_loader 回調作用一樣,但是 user_loader 回調只接受 Flask 請求而不是一個 user_id。

例如,爲了同時支持一個 url 參數和使用 Authorization 頭的基本用戶認證的登錄:

@login_manager.request_loader
def load_user_from_request(request):

    # first, try to login using the api_key url arg
    api_key = request.args.get('api_key')
    if api_key:
        user = User.query.filter_by(api_key=api_key).first()
        if user:
            return user

    # next, try to login using Basic Auth
    api_key = request.headers.get('Authorization')
    if api_key:
        api_key = api_key.replace('Basic ', '', 1)
        try:
            api_key = base64.b64decode(api_key)
        except TypeError:
            pass
        user = User.query.filter_by(api_key=api_key).first()
        if user:
            return user

    # finally, return None if both methods did not login the user
    return None

匿名用戶

默認情況下,當一個用戶沒有真正地登錄,current_user 被設置成一個 AnonymousUserMixin 對象。它由如下的屬性和方法:

is_active 和 is_authenticated 的值爲 False
is_anonymous 的值爲 True
get_id() 返回 None
如果需要爲匿名用戶定製一些需求(比如,需要一個權限域),你可以向 LoginManager 提供一個創建匿名用戶的回調(類或工廠函數):

login_manager.anonymous_user = MyAnonymousUser

記住我

“記住我”的功能很難實現。但是,Flask-Login 幾乎透明地實現它 - 只要把 remember=True 傳遞給 login_user。一個 cookie 將會存儲在用戶計算機中,如果用戶會話中沒有用戶 ID 的話,Flask-Login 會自動地從 cookie 中恢復用戶 ID。cookie 是防纂改的,因此如果用戶纂改過它(比如,使用其它的一些東西來代替用戶的 ID),它就會被拒絕,就像不存在。

該層功能是被自動實現的。但你能(且應該,如果你的應用處理任何敏感的數據)提供 額外基礎工作來增強你記住的 cookie 的安全性。

發佈了22 篇原創文章 · 獲贊 11 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章