Flask 擴展 用戶會話


pip install flask-login

接下來創建擴展對象實例:

from flask import Flask
from flask_login import LoginManager
 
app = Flask(__name__)
login_manager = LoginManager(app)

同時,你可以對LoginManager對象賦上配置參數:

# 設置登錄視圖的名稱,如果一個未登錄用戶請求一個只有登錄用戶才能訪問的視圖,
# 則閃現一條錯誤消息,並重定向到這里設置的登錄視圖。
# 如果未設置登錄視圖,則直接返回401錯誤。
login_manager.login_view = 'login'
# 設置當未登錄用戶請求一個只有登錄用戶才能訪問的視圖時,閃現的錯誤消息的內容,
# 默認的錯誤消息是:Please log in to access this page.。
login_manager.login_message = 'Unauthorized User'
# 設置閃現的錯誤消息的類別
login_manager.login_message_category = "info"

編寫用戶類

使用Flask-Login之前,你需要先定義用戶類,該類必須實現以下三個屬性和一個方法:

屬性 is_authenticated

  當用戶登錄成功后,該屬性為True。

屬性 is_active

  如果該用戶賬號已被激活,且該用戶已登錄成功,則此屬性為True。

屬性 is_anonymous

  是否為匿名用戶(未登錄用戶)。

方法 get_id()

  每個用戶都必須有一個唯一的標識符作為ID,該方法可以返回當前用戶的ID,這里ID必須是Unicode。

因為每次寫個用戶類很麻煩,Flask-Login提供了”UserMixin”類,你可以直接繼承它即可:

from flask_login import UserMixin
 
class User(UserMixin):
    pass

從會話或請求中加載用戶

在編寫登錄登出視圖前,我們要先寫一個加載用戶對象的方法。它的功能是根據傳入的用戶ID,構造一個新的用戶類的對象。為了簡化范例,我們不引入數據庫,而是在列表里定義用戶記錄。

# 用戶記錄表
users = [
    {'username': 'Tom', 'password': '111111'},
    {'username': 'Michael', 'password': '123456'}
]
 
# 通過用戶名,獲取用戶記錄,如果不存在,則返回None
def query_user(username):
    for user in users:
        if user['username'] == username:
            return user
 
# 如果用戶名存在則構建一個新的用戶類對象,並使用用戶名作為ID
# 如果不存在,必須返回None
@login_manager.user_loader
def load_user(username):
    if query_user(username) is not None:
        curr_user = User()
        curr_user.id = username
        return curr_user

上述代碼中,通過”@login_manager.user_loader”裝飾器修飾的方法,既是我們要實現的加載用戶對象方法。它是一個回調函數,在每次請求過來后,Flask-Login都會從Session中尋找”user_id”的值,如果找到的話,就會用這個”user_id”值來調用此回調函數,並構建一個用戶類對象。因此,沒有這個回調的話,Flask-Login將無法工作。

有一個問題,啟用Session的話一定需要客戶端允許Cookie,因為Session ID是保存在Cookie中的,如果Cookie被禁用了怎么辦?那我們的應用只好通過請求參數將用戶信息帶過來,一般情況下會使用一個動態的Token來表示登錄用戶的信息。此時,我們就不能依靠”@login_manager.user_loader”回調,而是使用”@login_manager.request_loader”回調。

from flask import request
 
# 從請求參數中獲取Token,如果Token所對應的用戶存在則構建一個新的用戶類對象
# 並使用用戶名作為ID,如果不存在,必須返回None
@login_manager.request_loader
def load_user_from_request(request):
    username = request.args.get('token')
    if query_user(username) is not None:
        curr_user = User()
        curr_user.id = username
        return curr_user

為了簡化代碼,上面的例子就直接使用用戶名作為Token了,實際項目中,大家還是要用一個復雜的算法來驗證Token。

登錄及登出

一切准備就緒,我們開始實現登錄視圖:

from flask import render_template, redirect, url_for, flash
from flask_login import login_user
 
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form.get('username')
        user = query_user(username)
        # 驗證表單中提交的用戶名和密碼
        if user is not None and request.form['password'] == user['password']:
            curr_user = User()
            curr_user.id = username
 
            # 通過Flask-Login的login_user方法登錄用戶
            login_user(curr_user)
 
            # 如果請求中有next參數,則重定向到其指定的地址,
            # 沒有next參數,則重定向到"index"視圖
            next = request.args.get('next')
            return redirect(next or url_for('index'))
 
        flash('Wrong username or password!')
    # GET 請求
    return render_template('login.html')

上述代碼同之前Login視圖最大的不同就是你在用戶驗證通過后,需要調用Flask-Login擴展提供的”login_user()”方法來讓用戶登錄,該方法需傳入用戶類對象。這個”login_user()”方法會幫助你操作用戶Session,並且會在請求上下文中記錄用戶信息。另外,在具體實現時,建議大家對”next”參數值作驗證,避免被URL注入攻擊。

“login.html”模板很簡單,就是顯示一個用戶名密碼的表單:

<!doctype html>
<title>Login Sample</title>
<h1>Login</h1>
{% with messages = get_flashed_messages() %}
    <div>{{ messages[0] }}</div>
{% endwith %}
<form action="{{ url_for('login') }}" method="POST">
    <input type="text" name="username" id="username" placeholder="Username"></input>
    <input type="password" name="password" id="password" placeholder="Password"></input>
    <input type="submit" name="submit"></input>
</form>

接下來,讓我們寫個index視圖

from flask_login import current_user, login_required
 
@app.route('/')
@login_required
def index():
    return 'Logged in as: %s' % current_user.get_id()

裝飾器”@login_required”確保只有登錄用戶才能訪問這個index視圖,Flask-Login幫我們實現了這個裝飾器。如果用戶未登錄,它就會將頁面重定向到登錄視圖,也就是我們在第一節中配置的”login_manager.login_view”的視圖。

同時,重定向的地址會自動加上”next”參數,參數的值是當前用戶請求的地址,這樣,登錄成功后就會跳轉回當前視圖。可以看到我們對於用戶登錄所需要的操作,這個裝飾器基本都實現了

 

Flask-Login還提供了”current_user”代理,可以訪問到登錄用戶的用戶類對象。我們在模板中也可以使用這個代理。讓我們再寫一個home視圖:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM