如何使用 Session

Django 完整支援匿名 session。session 框架讓您可以針對每個網站訪客儲存和檢索任意資料。它將資料儲存在伺服器端,並抽象化 cookie 的傳送和接收。Cookie 包含 session ID – 而不是資料本身 (除非您使用 基於 cookie 的後端)。

啟用 session

Session 是透過一段 中介軟體 來實作的。

若要啟用 session 功能,請執行以下步驟:

  • 編輯 MIDDLEWARE 設定,並確保其包含 'django.contrib.sessions.middleware.SessionMiddleware'。由 django-admin startproject 建立的預設 settings.py 已啟用 SessionMiddleware

如果您不想使用 session,您可以從 MIDDLEWARE 中移除 SessionMiddleware 行,並從您的 INSTALLED_APPS 中移除 'django.contrib.sessions'。這會為您節省一點點的額外負擔。

設定 session 引擎

預設情況下,Django 會將 session 儲存在您的資料庫中 (使用 django.contrib.sessions.models.Session 模型)。雖然這很方便,但在某些設定中,將 session 資料儲存在其他地方會更快,因此可以設定 Django 將 session 資料儲存在您的檔案系統或快取中。

使用資料庫支援的 session

如果您想使用資料庫支援的 session,您需要將 'django.contrib.sessions' 新增至您的 INSTALLED_APPS 設定。

在您設定好安裝後,執行 manage.py migrate 來安裝儲存 session 資料的單一資料庫表格。

使用快取 session

為了獲得更好的效能,您可能會想使用基於快取的 session 後端。

若要使用 Django 的快取系統儲存 session 資料,您首先需要確保您已設定好快取;請參閱 快取文件 以取得詳細資訊。

警告

您應該只在使用 Memcached 或 Redis 快取後端時才使用基於快取的 session。本機記憶體快取後端不會保留足夠的資料來成為好的選擇,而且直接使用檔案或資料庫 session 會比透過檔案或資料庫快取後端傳送所有內容更快。此外,本機記憶體快取後端並非多程序安全,因此可能不是生產環境的好選擇。

如果您在 CACHES 中定義了多個快取,Django 將使用預設快取。若要使用其他快取,請將 SESSION_CACHE_ALIAS 設定為該快取的名稱。

一旦設定好您的快取,您必須在資料庫支援的快取或非持久快取之間做選擇。

快取資料庫後端 (cached_db) 使用寫入式快取 – session 寫入會依序套用至資料庫和快取。如果寫入快取失敗,將會處理該例外狀況,並透過 session 記錄器 記錄,以避免讓其他成功的寫入操作失敗。

在 Django 5.1 中變更

新增了寫入快取時的例外狀況處理和記錄。

Session 讀取會使用快取,如果資料已從快取中清除,則會使用資料庫。若要使用此後端,請將 SESSION_ENGINE 設定為 "django.contrib.sessions.backends.cached_db",並依照 使用資料庫支援的 session 的設定指示。

快取後端 (cache) 只將 session 資料儲存在您的快取中。這比較快,因為它避免了資料庫的持久性,但您必須考慮快取資料被清除時會發生什麼事。如果快取填滿或快取伺服器重新啟動,就會發生清除,而且這意味著 session 資料會遺失,包括使用者登出。若要使用此後端,請將 SESSION_ENGINE 設定為 "django.contrib.sessions.backends.cache"

透過使用持久快取 (例如具有適當設定的 Redis),可以使快取後端持久化。但是,除非您的快取絕對設定為具有足夠的持久性,否則請選擇快取資料庫後端。這可以避免因生產環境中不可靠的資料儲存所造成的邊緣案例。

使用基於檔案的 session

若要使用基於檔案的 session,請將 SESSION_ENGINE 設定設定為 "django.contrib.sessions.backends.file"

您可能也會想要設定 SESSION_FILE_PATH 設定 (預設為 tempfile.gettempdir() 的輸出,最可能是 /tmp),以控制 Django 儲存 session 檔案的位置。請務必檢查您的 Web 伺服器是否有權限讀取和寫入此位置。

在視圖中使用 session

SessionMiddleware 啟用時,每個 HttpRequest 物件 (任何 Django 視圖函數的第一個引數) 都會有一個 session 屬性,這是一個類似字典的物件。

您可以在視圖中的任何點讀取和寫入 request.session。您可以多次編輯它。

class backends.base.SessionBase

這是所有 session 物件的基礎類別。它具有以下標準字典方法:

__getitem__(key)

範例:fav_color = request.session['fav_color']

__setitem__(key, value)

範例:request.session['fav_color'] = 'blue'

__delitem__(key)

範例:del request.session['fav_color']。如果給定的 key 不存在於 session 中,則會引發 KeyError

__contains__(key)

範例:'fav_color' in request.session

get(key, default=None)
aget(key, default=None)

非同步版本aget()

範例:fav_color = request.session.get('fav_color', 'red')

在 Django 5.1 中變更

新增了 aget() 函數。

aset(key, value)
Django 5.1 新增功能。

範例:await request.session.aset('fav_color', 'red')

update(dict)
aupdate(dict)

非同步版本aupdate()

範例:request.session.update({'fav_color': 'red'})

在 Django 5.1 中變更

新增了 aupdate() 函數。

pop(key, default=__not_given)
apop(key, default=__not_given)

非同步版本apop()

範例:fav_color = request.session.pop('fav_color', 'blue')

在 Django 5.1 中變更

新增了 apop() 函數。

keys()
akeys()

非同步版本akeys()

在 Django 5.1 中變更

新增了 akeys() 函數。

values()
avalues()

非同步版本avalues()

在 Django 5.1 中變更

新增了 avalues() 函數。

has_key(key)
ahas_key(key)

非同步版本ahas_key()

在 Django 5.1 中變更

新增了 ahas_key() 函數。

items()
aitems()

非同步版本aitems()

在 Django 5.1 中變更

新增了 aitems() 函數。

setdefault()
asetdefault()

非同步版本asetdefault()

在 Django 5.1 中變更

新增了 asetdefault() 函數。

clear()

它也具有這些方法:

flush()
aflush()

非同步版本aflush()

從 session 中刪除目前的 session 資料,並刪除 session cookie。如果您想確保使用者瀏覽器無法再次存取先前的 session 資料(例如,django.contrib.auth.logout() 函數會呼叫它),則可以使用此方法。

在 Django 5.1 中變更

新增了 aflush() 函數。

非同步版本aset_test_cookie()

設定一個測試 cookie,以判斷使用者的瀏覽器是否支援 cookie。由於 cookie 的運作方式,您必須等到使用者下次頁面請求才能測試此功能。請參閱下方設定測試 cookie以取得更多資訊。

在 Django 5.1 中變更

新增了 aset_test_cookie() 函數。

非同步版本atest_cookie_worked()

根據使用者的瀏覽器是否接受測試 cookie,傳回 TrueFalse。由於 cookie 的運作方式,您必須在先前的個別頁面請求中呼叫 set_test_cookie()aset_test_cookie()。請參閱下方設定測試 cookie以取得更多資訊。

在 Django 5.1 中變更

新增了 atest_cookie_worked() 函數。

非同步版本adelete_test_cookie()

刪除測試 cookie。請在用完後使用此方法來清理。

在 Django 5.1 中變更

新增了 adelete_test_cookie() 函數。

傳回設定 SESSION_COOKIE_AGE 的值。可以在自訂 session 後端中覆寫此設定。

set_expiry(value)
aset_expiry(value)

非同步版本: aset_expiry()

設定 Session 的過期時間。您可以傳入不同的值

  • 如果 value 為整數,Session 將在閒置這麼多秒後過期。例如,呼叫 request.session.set_expiry(300) 會使 Session 在 5 分鐘後過期。

  • 如果 valuedatetimetimedelta 物件,Session 將在該特定日期/時間過期。

  • 如果 value0,使用者的 Session Cookie 將在使用者關閉網頁瀏覽器時過期。

  • 如果 valueNone,Session 將恢復使用全域 Session 過期策略。

讀取 Session 不會被視為過期目的的活動。Session 過期時間是從 Session 最後一次被修改時開始計算。

在 Django 5.1 中變更

aset_expiry() 函式已新增。

get_expiry_age()
aget_expiry_age()

非同步版本: aget_expiry_age()

傳回此 Session 到期前的秒數。對於沒有自訂過期時間的 Session(或設定為在瀏覽器關閉時過期的 Session),這將等於 SESSION_COOKIE_AGE

此函式接受兩個可選的關鍵字參數

  • modification:Session 的最後修改時間,為 datetime 物件。預設為目前時間。

  • expiry:Session 的過期資訊,為 datetime 物件、int (以秒為單位) 或 None。預設為 set_expiry()/aset_expiry() 儲存在 Session 中的值(如果有的話),否則為 None

注意

Session 後端使用此方法來決定儲存 Session 時 Session 過期前的秒數。它實際上不適用於該上下文之外的用途。

特別是,雖然**可以**在您擁有正確的 modification 值**並且** expiry 設定為 datetime 物件的情況下**才**可以判斷 Session 的剩餘存活時間,其中您確實擁有 modification 值,但手動計算過期時間會更直接。

expires_at = modification + timedelta(seconds=settings.SESSION_COOKIE_AGE)
在 Django 5.1 中變更

aget_expiry_age() 函式已新增。

get_expiry_date()
aget_expiry_date()

非同步版本: aget_expiry_date()

傳回此 Session 將過期的日期。對於沒有自訂過期時間的 Session(或設定為在瀏覽器關閉時過期的 Session),這將等於 SESSION_COOKIE_AGE 秒後的日期。

此函式接受與 get_expiry_age() 相同的關鍵字參數,並且適用類似的用法說明。

在 Django 5.1 中變更

aget_expiry_date() 函式已新增。

get_expire_at_browser_close()
aget_expire_at_browser_close()

非同步版本: aget_expire_at_browser_close()

傳回 TrueFalse,取決於使用者的 Session Cookie 是否會在使用者關閉網頁瀏覽器時過期。

在 Django 5.1 中變更

aget_expire_at_browser_close() 函式已新增。

clear_expired()
aclear_expired()

非同步版本: aclear_expired()

從 Session 儲存區中移除過期的 Session。此類別方法由 clearsessions 呼叫。

在 Django 5.1 中變更

aclear_expired() 函式已新增。

cycle_key()
acycle_key()

非同步版本: acycle_key()

建立新的 Session 金鑰,同時保留目前的 Session 資料。 django.contrib.auth.login() 呼叫此方法來減輕 Session 固定攻擊。

在 Django 5.1 中變更

acycle_key() 函式已新增。

Session 序列化

預設情況下,Django 使用 JSON 序列化 Session 資料。您可以使用 SESSION_SERIALIZER 設定來自訂 Session 序列化格式。即使 撰寫自己的序列化程式 中描述了警告,我們仍然強烈建議堅持使用 JSON 序列化,尤其是在您使用 Cookie 後端時

例如,如果您使用 pickle 來序列化 Session 資料,以下是一個攻擊情境。如果您使用的是簽名 Cookie Session 後端,並且 SECRET_KEY(或 SECRET_KEY_FALLBACKS 的任何金鑰)被攻擊者知道(Django 沒有導致洩漏的固有漏洞),攻擊者可能會將字串插入他們的 Session 中,當解封裝時,會在伺服器上執行任意程式碼。執行此操作的技術很簡單,並且在網路上很容易取得。雖然 Cookie Session 儲存會簽署 Cookie 儲存的資料以防止竄改,但 SECRET_KEY 洩漏會立即升級為遠端程式碼執行漏洞。

綑綁的序列化程式

class serializers.JSONSerializer

django.core.signing 中 JSON 序列化程式的包裝。只能序列化基本資料類型。

此外,由於 JSON 僅支援字串金鑰,請注意在 request.session 中使用非字串金鑰將無法如預期般運作

>>> # initial assignment
>>> request.session[0] = "bar"
>>> # subsequent requests following serialization & deserialization
>>> # of session data
>>> request.session[0]  # KeyError
>>> request.session["0"]
'bar'

同樣地,無法在 JSON 中編碼的資料,例如非 UTF8 位元組(如 '\xd9',會引發 UnicodeDecodeError),則無法儲存。

請參閱撰寫自己的序列化程式章節,以取得更多有關 JSON 序列化限制的詳細資訊。

撰寫自己的序列化程式

請注意,JSONSerializer 無法處理任意的 Python 資料型別。如同常見的情況,便利性與安全性之間存在取捨。如果您希望在 JSON 後端的 session 中儲存更進階的資料型別,包括 datetimeDecimal,您需要編寫自訂的序列化器(serializer)(或在將這些值儲存到 request.session 之前,將其轉換為可 JSON 序列化的物件)。雖然序列化這些值通常很簡單(DjangoJSONEncoder 可能很有幫助),但編寫一個能夠可靠地取回您放入的相同內容的解碼器會更複雜。例如,您可能會返回一個 datetime,但實際上它只是一個剛好與為 datetime 選擇的格式相同的字串。

您的序列化器類別必須實作兩個方法:dumps(self, obj)loads(self, data),分別用於序列化和反序列化 session 資料的字典。

Session 物件指南

  • request.session 上使用一般的 Python 字串作為字典的鍵。這更像是一種慣例,而不是硬性規定。

  • 以底線開頭的 Session 字典鍵保留給 Django 內部使用。

  • 不要用新的物件覆蓋 request.session,也不要存取或設定其屬性。請像使用 Python 字典一樣使用它。

範例

這個簡單的視圖在使用者發布評論後,將 has_commented 變數設定為 True。它不允許使用者發布多次評論

def post_comment(request, new_comment):
    if request.session.get("has_commented", False):
        return HttpResponse("You've already commented.")
    c = comments.Comment(comment=new_comment)
    c.save()
    request.session["has_commented"] = True
    return HttpResponse("Thanks for your comment!")

這個簡單的視圖登入網站的「會員」

def login(request):
    m = Member.objects.get(username=request.POST["username"])
    if m.check_password(request.POST["password"]):
        request.session["member_id"] = m.id
        return HttpResponse("You're logged in.")
    else:
        return HttpResponse("Your username and password didn't match.")

…而這個視圖則根據上面的 login() 登出會員

def logout(request):
    try:
        del request.session["member_id"]
    except KeyError:
        pass
    return HttpResponse("You're logged out.")

標準的 django.contrib.auth.logout() 函式實際上做了更多的事情來防止無意中的資料洩漏。它會呼叫 request.sessionflush() 方法。我們使用這個範例來示範如何使用 session 物件,而不是作為完整的 logout() 實作。

設定測試 Cookie

為了方便起見,Django 提供了一種方法來測試使用者的瀏覽器是否接受 cookie。在視圖中呼叫 request.sessionset_test_cookie() 方法,並在後續的視圖中呼叫 test_cookie_worked() 方法 – 不要在同一個視圖呼叫中執行。

由於 cookie 的運作方式,set_test_cookie()test_cookie_worked() 之間的這個不協調的分裂是必要的。當您設定一個 cookie 時,您實際上無法得知瀏覽器是否接受它,直到瀏覽器下次發出請求。

最好使用 delete_test_cookie() 來清除。在您驗證測試 cookie 已正常運作後執行此操作。

以下是一個典型的使用範例

from django.http import HttpResponse
from django.shortcuts import render


def login(request):
    if request.method == "POST":
        if request.session.test_cookie_worked():
            request.session.delete_test_cookie()
            return HttpResponse("You're logged in.")
        else:
            return HttpResponse("Please enable cookies and try again.")
    request.session.set_test_cookie()
    return render(request, "foo/login_form.html")
在 Django 5.1 中變更

新增了對在非同步視圖函式中設定測試 cookie 的支援。

在視圖之外使用 session

注意

本節中的範例直接從 django.contrib.sessions.backends.db 後端匯入 SessionStore 物件。在您自己的程式碼中,您應該考慮從 SESSION_ENGINE 指定的 session 引擎匯入 SessionStore,如下所示

>>> from importlib import import_module
>>> from django.conf import settings
>>> SessionStore = import_module(settings.SESSION_ENGINE).SessionStore

提供了一個 API 來在視圖之外操作 session 資料

>>> from django.contrib.sessions.backends.db import SessionStore
>>> s = SessionStore()
>>> # stored as seconds since epoch since datetimes are not serializable in JSON.
>>> s["last_login"] = 1376587691
>>> s.create()
>>> s.session_key
'2b1189a188b44ad18c35e113ac6ceead'
>>> s = SessionStore(session_key="2b1189a188b44ad18c35e113ac6ceead")
>>> s["last_login"]
1376587691

SessionStore.create() 旨在建立一個新的 session(即未從 session 儲存區載入且 session_key=None 的 session)。save() 旨在儲存現有的 session(即從 session 儲存區載入的 session)。對新的 session 呼叫 save() 也可能有效,但產生與現有 session 衝突的 session_key 的機率很小。create() 呼叫 save() 並循環執行,直到產生未使用的 session_key

如果您使用 django.contrib.sessions.backends.db 後端,則每個 session 都是一個普通的 Django 模型。Session 模型定義在 django/contrib/sessions/models.py 中。由於它是一個普通的模型,您可以使用 Django 資料庫 API 來存取 session

>>> from django.contrib.sessions.models import Session
>>> s = Session.objects.get(pk="2b1189a188b44ad18c35e113ac6ceead")
>>> s.expire_date
datetime.datetime(2005, 8, 20, 13, 35, 12)

請注意,您需要呼叫 get_decoded() 來取得 session 字典。這是必要的,因為字典是以編碼格式儲存的

>>> s.session_data
'KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj...'
>>> s.get_decoded()
{'user_id': 42}

何時儲存 session

預設情況下,只有在 session 被修改時,Django 才會儲存到 session 資料庫 – 也就是說,如果它的任何字典值被指派或刪除

# Session is modified.
request.session["foo"] = "bar"

# Session is modified.
del request.session["foo"]

# Session is modified.
request.session["foo"] = {}

# Gotcha: Session is NOT modified, because this alters
# request.session['foo'] instead of request.session.
request.session["foo"]["bar"] = "baz"

在上面範例的最後一種情況中,我們可以透過設定 session 物件上的 modified 屬性,明確告知 session 物件它已被修改

request.session.modified = True

要變更此預設行為,請將 SESSION_SAVE_EVERY_REQUEST 設定設定為 True。當設定為 True 時,Django 將在每個請求上將 session 儲存到資料庫。

請注意,只有在建立或修改 session 時才會傳送 session cookie。如果 SESSION_SAVE_EVERY_REQUESTTrue,則會在每個請求上傳送 session cookie。

同樣地,每次傳送 session cookie 時,session cookie 的 expires 部分都會更新。

如果回應的狀態碼為 500,則不會儲存 session。

瀏覽器長度 session 與持久性 session

您可以使用 SESSION_EXPIRE_AT_BROWSER_CLOSE 設定來控制 session 架構使用瀏覽器長度 session 還是持久性 session。

預設情況下,SESSION_EXPIRE_AT_BROWSER_CLOSE 設定為 False,這表示 session cookie 將在使用者的瀏覽器中儲存 SESSION_COOKIE_AGE 的時間。如果您不希望使用者每次開啟瀏覽器時都必須登入,請使用此設定。

如果 SESSION_EXPIRE_AT_BROWSER_CLOSE 設定為 True,Django 將使用瀏覽器長度 cookie – 在使用者關閉瀏覽器後立即過期的 cookie。如果您希望使用者每次開啟瀏覽器時都必須登入,請使用此設定。

此設定是一個全域預設值,可以透過明確呼叫 request.sessionset_expiry() 方法,在每個 session 層級覆寫,如上面的 在視圖中使用 session 中所述。

注意

某些瀏覽器(例如 Chrome)提供了允許使用者在關閉並重新開啟瀏覽器後繼續瀏覽 session 的設定。在某些情況下,這可能會干擾 SESSION_EXPIRE_AT_BROWSER_CLOSE 設定,並防止 session 在關閉瀏覽器時過期。請在測試已啟用 SESSION_EXPIRE_AT_BROWSER_CLOSE 設定的 Django 應用程式時注意這一點。

清除 session 儲存區

當使用者在您的網站上建立新的 session 時,session 資料可能會累積在您的 session 儲存區中。如果您使用資料庫後端,django_session 資料庫表格將會成長。如果您使用檔案後端,您的暫存目錄將包含越來越多的檔案。

為了理解這個問題,請考慮使用資料庫後端會發生什麼情況。當使用者登入時,Django 會在 django_session 資料庫表格中新增一列。每次 session 資料變更時,Django 都會更新這一列。如果使用者手動登出,Django 會刪除該列。但是,如果使用者沒有登出,則永遠不會刪除該列。檔案後端也會發生類似的過程。

Django 並提供自動清除過期 session 的功能。因此,您有責任定期清除過期的 session。Django 提供了一個用於此目的的清理管理命令:clearsessions。建議定期呼叫此命令,例如每天透過 cron job 執行。

請注意,快取後端不會有這個問題,因為快取會自動刪除過時的資料。cookie 後端也不會有這個問題,因為 session 資料是儲存在使用者的瀏覽器中。

設定

一些 Django 設定 可讓您控制 session 行為。

Session 安全性

網站內的子網域能夠在客戶端設定整個網域的 cookie。如果允許來自不受信任使用者控制的子網域設定 cookie,這會導致 session 固定攻擊的風險。

例如,攻擊者可以登入 good.example.com 並取得其帳戶的有效 session。如果攻擊者控制了 bad.example.com,他們可以使用它將他們的 session 金鑰傳送給您,因為子網域可以設定 *.example.com 的 cookie。當您訪問 good.example.com 時,您會以攻擊者的身分登入,並且可能會不小心將您的敏感個人資料(例如信用卡資訊)輸入到攻擊者的帳戶中。

另一個可能的攻擊是,如果 good.example.com 將其 SESSION_COOKIE_DOMAIN 設定為 "example.com",這將導致該網站的 session cookie 被傳送到 bad.example.com

技術細節

  • 當使用 JSONSerializer 時,session 字典接受任何 json 可序列化的值。

  • Session 資料儲存在名為 django_session 的資料庫表格中。

  • Django 只有在需要時才會傳送 cookie。如果您沒有設定任何 session 資料,它就不會傳送 session cookie。

SessionStore 物件

在內部處理 session 時,Django 會使用來自對應 session 引擎的 session 儲存物件。依照慣例,session 儲存物件類別名為 SessionStore,並且位於 SESSION_ENGINE 指定的模組中。

Django 中所有可用的 SessionStore 子類別都實作了以下資料操作方法

這些方法透過 sync_to_async() 包裝後,提供非同步介面。如果可以使用非同步原生實作,則可以直接實作它們

為了建立自訂 session 引擎或自訂現有的 session 引擎,您可以建立一個新的類別,繼承自 SessionBase 或任何其他現有的 SessionStore 類別。

您可以擴充 session 引擎,但是使用資料庫支援的 session 引擎進行擴充通常需要一些額外的努力(詳細資訊請參閱下一節)。

在 Django 5.1 中變更

新增了 aexists()acreate()asave()adelete()aload()aclear_expired() 方法。

擴充資料庫支援的 session 引擎

透過繼承 AbstractBaseSessionSessionStore 類別,可以建立一個基於 Django 內建的資料庫支援 session 引擎(即 dbcached_db)的自訂資料庫支援 session 引擎。

AbstractBaseSessionBaseSessionManager 可從 django.contrib.sessions.base_session 匯入,這樣就可以在不包含 INSTALLED_APPS 中的 django.contrib.sessions 的情況下匯入它們。

class base_session.AbstractBaseSession

抽象基礎 session 模型。

session_key

主鍵。該欄位本身最多可以包含 40 個字元。目前的實作會產生一個 32 個字元的字串(隨機的數字和小寫 ASCII 字母序列)。

session_data

包含編碼和序列化 session 字典的字串。

expire_date

指定 session 過期的日期時間。

過期的 session 對使用者不可用,但是它們仍然可能會儲存在資料庫中,直到執行 clearsessions 管理命令。

classmethod get_session_store_class()

傳回要用於此 session 模型的 session 儲存類別。

get_decoded()

傳回已解碼的 session 資料。

解碼由 session 儲存類別執行。

您也可以透過繼承 BaseSessionManager 來客製化模型管理員。

class base_session.BaseSessionManager
encode(session_dict)

傳回以字串形式序列化和編碼的給定 session 字典。

編碼由與模型類別關聯的 session 儲存類別執行。

save(session_key, session_dict, expire_date)

儲存所提供 session 金鑰的 session 資料,如果資料為空,則刪除 session。

透過覆寫以下描述的方法和屬性,可以實現 SessionStore 類別的客製化。

class backends.db.SessionStore

實作資料庫支援的 session 儲存。

classmethod get_model_class()

如果您需要自訂 session 模型,請覆寫此方法以傳回自訂 session 模型。

create_model_instance(data)

傳回 session 模型物件的新執行個體,該物件表示目前的 session 狀態。

覆寫此方法可以修改 session 模型資料,然後再將其儲存到資料庫中。

class backends.cached_db.SessionStore

實作快取資料庫支援的 session 儲存。

cache_key_prefix

新增到 session 金鑰的前綴,以建立快取金鑰字串。

範例

以下範例顯示了一個自訂資料庫支援的 session 引擎,其中包含一個額外的資料庫欄位來儲存帳戶 ID(從而提供一個選項,可以查詢資料庫以取得帳戶的所有活動 session)。

from django.contrib.sessions.backends.db import SessionStore as DBStore
from django.contrib.sessions.base_session import AbstractBaseSession
from django.db import models


class CustomSession(AbstractBaseSession):
    account_id = models.IntegerField(null=True, db_index=True)

    @classmethod
    def get_session_store_class(cls):
        return SessionStore


class SessionStore(DBStore):
    @classmethod
    def get_model_class(cls):
        return CustomSession

    def create_model_instance(self, data):
        obj = super().create_model_instance(data)
        try:
            account_id = int(data.get("_auth_user_id"))
        except (ValueError, TypeError):
            account_id = None
        obj.account_id = account_id
        return obj

如果您要從 Django 的內建 cached_db session 儲存遷移到基於 cached_db 的自訂 session 儲存,您應該覆寫快取金鑰前綴,以防止命名空間衝突。

class SessionStore(CachedDBStore):
    cache_key_prefix = "mysessions.custom_cached_db_backend"

    # ...

URL 中的 Session ID

Django session 框架完全且僅限於基於 cookie。它不會像 PHP 那樣在不得已的情況下將 session ID 放入 URL 中。這是有意為之的設計決策。這種行為不僅會使 URL 變得難看,還會使您的網站容易受到透過「Referer」標頭盜取 session ID 的攻擊。

返回頂部