日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Flask扩展系列(八)–用户会话管理

發(fā)布時間:2023/12/9 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Flask扩展系列(八)–用户会话管理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

安裝和啟用

遵循標準的Flask擴展安裝和啟用方式,先通過pip來安裝擴展:

$ pip install Flask-Login

接下來創(chuàng)建擴展對象實例:

1

2

3

4

5

from flask import Flask

from flask.ext.login import LoginManager

?

app = Flask(__name__)

login_manager = LoginManager(app)

?

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

1

2

3

4

5

6

7

8

9

# 設置登錄視圖的名稱,如果一個未登錄用戶請求一個只有登錄用戶才能訪問的視圖,

# 則閃現(xiàn)一條錯誤消息,并重定向到這里設置的登錄視圖。

# 如果未設置登錄視圖,則直接返回401錯誤。

login_manager.login_view = 'login'

# 設置當未登錄用戶請求一個只有登錄用戶才能訪問的視圖時,閃現(xiàn)的錯誤消息的內(nèi)容,

# 默認的錯誤消息是:Please log in to access this page.。

login_manager.login_message = 'Unauthorized User'

# 設置閃現(xiàn)的錯誤消息的類別

login_manager.login_message_category = "info"

?

編寫用戶類

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

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

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

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

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

  • 屬性?is_authenticated
  • 屬性?is_active
  • 屬性?is_anonymous
  • 方法?get_id()
  • 因為每次寫個用戶類很麻煩,Flask-Login提供了”UserMixin”類,你可以直接繼承它即可:

    1

    2

    3

    4

    from flask.ext.login import UserMixin

    ?

    class User(UserMixin):

    ????pass

    ?

    從會話或請求中加載用戶

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

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    # 用戶記錄表

    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”裝飾器修飾的方法,既是我們要實現(xiàn)的加載用戶對象方法。它是一個回調(diào)函數(shù),在每次請求過來后,Flask-Login都會從Session中尋找”user_id”的值,如果找到的話,就會用這個”user_id”值來調(diào)用此回調(diào)函數(shù),并構建一個用戶類對象。因此,沒有這個回調(diào)的話,Flask-Login將無法工作。

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

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    from flask import request

    ?

    # 從請求參數(shù)中獲取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。

    登錄及登出

    一切準備就緒,我們開始實現(xiàn)登錄視圖:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    from flask import render_template, redirect, url_for, flash

    from flask.ext.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參數(shù),則重定向到其指定的地址,

    ????????????# 沒有next參數(shù),則重定向到"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視圖最大的不同就是你在用戶驗證通過后,需要調(diào)用Flask-Login擴展提供的”login_user()”方法來讓用戶登錄,該方法需傳入用戶類對象。這個”login_user()”方法會幫助你操作用戶Session,并且會在請求上下文中記錄用戶信息。另外,在具體實現(xiàn)時,建議大家對”next”參數(shù)值作驗證,避免被URL注入攻擊。

    “l(fā)ogin.html”模板很簡單,就是顯示一個用戶名密碼的表單:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    <!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視圖:

    1

    2

    3

    4

    5

    6

    from flask.ext.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幫我們實現(xiàn)了這個裝飾器。如果用戶未登錄,它就會將頁面重定向到登錄視圖,也就是我們在第一節(jié)中配置的”login_manager.login_view”的視圖。

    同時,重定向的地址會自動加上”next”參數(shù),參數(shù)的值是當前用戶請求的地址,這樣,登錄成功后就會跳轉(zhuǎn)回當前視圖。可以看到我們對于用戶登錄所需要的操作,這個裝飾器基本都實現(xiàn)了,很方便吧!

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

    1

    2

    3

    4

    @app.route('/home')

    @login_required

    def home():

    ????return render_template('hello.html')

    模板代碼如下:

    1

    2

    3

    4

    5

    <!doctype html>

    <title>Login Sample</title>

    {% if current_user.is_authenticated %}

    ??<h1>Hello {{ current_user.get_id() }}!</h1>

    {% endif %}

    在上面的模板代碼中,我們直接訪問了”current_user”對象的屬性和方法。

    登出視圖也很簡單,Flask-Login提供了”logout_user()”方法來幫助你清理用戶Session。

    1

    2

    3

    4

    5

    6

    7

    from flask.ext.login import logout_user

    ?

    @app.route('/logout')

    @login_required

    def logout():

    ????logout_user()

    ????return 'Logged out successfully!'

    ?

    自定義未授權訪問的處理方法

    “@login_required”裝飾器對于未登錄用戶訪問的默認處理是重定向到登錄視圖,如果我們不想它這么做的話,可以自定義處理方法:

    1

    2

    3

    @login_manager.unauthorized_handler

    def unauthorized_handler():

    ????return 'Unauthorized'

    這個”@login_manager.unauthorized_handler”裝飾器所修飾的方法就會代替”@login_required”裝飾器的默認處理方法。有了上面的代碼,當未登錄用戶訪問index視圖時,頁面就會直接返回”Unauthorized”信息。

    Remember Me

    在登錄視圖中,調(diào)用”login_user()”方法時,傳入”remember=True”參數(shù),即可實現(xiàn)“記住我”功能:

    1

    2

    3

    ...

    ????????????login_user(curr_user, remember=True)

    ...

    Flask-Login是通過在Cookie實現(xiàn)的,它會在Cookie中添加一個”remember_token”字段來記住之前登錄的用戶信息,所以禁用Cookie的話,該功能將無法工作。

    Fresh登錄

    當用戶通過賬號和密碼登錄后,Flask-Login會將其標識為Fresh登錄,即在Session中設置”_fresh”字段為True。而用戶通過Remember Me自動登錄的話,則不標識為Fresh登錄。對于”@login_required”裝飾器修飾的視圖,是否Fresh登錄都可以訪問,但是有些情況下,我們會強制要求用戶登錄一次,比如修改登錄密碼,這時候,我們可以用”@fresh_login_required”裝飾器來修飾該視圖。這樣,通過Remember Me自動登錄的用戶,將無法訪問該視圖:

    1

    2

    3

    4

    5

    6

    from flask.ext.login import fresh_login_required

    ?

    @app.route('/home')

    @fresh_login_required

    def home():

    ????return 'Logged in as: %s' % current_user.get_id()

    ?

    會話保護

    Flask-Login自動啟用會話保護功能。對于每個請求,它會驗證用戶標識,這個標識是由客戶端IP地址和User Agent的值經(jīng)SHA512編碼而來。在用戶登錄成功時,Flask-Login就會將這個值保存起來以便后續(xù)檢查。默認的會話保護模式是”basic”,為了加強安全性,你可以啟用強會話保護模式,方法是配置LoginManager實例對象中的”session_protection”屬性:

    1

    login_manager.session_protection = "strong"

    在”strong”模式下,一旦用戶標識檢查失敗,便會清空所用Session內(nèi)容,并且Remember Me也失效。而”basic”模式下,只是將登錄標為非Fresh登錄。你還可以將”login_manager.session_protection”置為None來取消會話保護。

    更多參考資料

    Flask-Login的官方文檔
    Flask-Login的源碼

    本篇的示例代碼可以在這里下載。

    格式日志發(fā)布于2016年4月29日作者Billy.J.Hee分類Python、編程標簽Flask、Login、Session

    文章導航

    上一上篇文章:Flask擴展系列(七)–表單

    下一下篇文章:Flask擴展系列(九)–HTTP認證

    《Flask擴展系列(八)–用戶會話管理》有3個想法

  • 張瑩說道:

    2017年5月7日 下午9:42

    利用Flask-Login和session進行用戶登錄管理具體區(qū)別是什么呢?

    如何利用session記錄其他需要保留的信息,例如上次訪問頁面的時間?

    多謝賜教!

  • 總結(jié)

    以上是生活随笔為你收集整理的Flask扩展系列(八)–用户会话管理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。