如何使用 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 記錄器 記錄,以避免讓其他成功的寫入操作失敗。
新增了寫入快取時的例外狀況處理和記錄。
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()
函數。
- set_test_cookie()¶
- aset_test_cookie()¶
非同步版本:
aset_test_cookie()
設定一個測試 cookie,以判斷使用者的瀏覽器是否支援 cookie。由於 cookie 的運作方式,您必須等到使用者下次頁面請求才能測試此功能。請參閱下方設定測試 cookie以取得更多資訊。
在 Django 5.1 中變更新增了
aset_test_cookie()
函數。
- test_cookie_worked()¶
- atest_cookie_worked()¶
非同步版本:
atest_cookie_worked()
根據使用者的瀏覽器是否接受測試 cookie,傳回
True
或False
。由於 cookie 的運作方式,您必須在先前的個別頁面請求中呼叫set_test_cookie()
或aset_test_cookie()
。請參閱下方設定測試 cookie以取得更多資訊。在 Django 5.1 中變更新增了
atest_cookie_worked()
函數。
- delete_test_cookie()¶
- adelete_test_cookie()¶
非同步版本:
adelete_test_cookie()
刪除測試 cookie。請在用完後使用此方法來清理。
在 Django 5.1 中變更新增了
adelete_test_cookie()
函數。
- get_session_cookie_age()¶
傳回設定
SESSION_COOKIE_AGE
的值。可以在自訂 session 後端中覆寫此設定。
- set_expiry(value)¶
- aset_expiry(value)¶
非同步版本:
aset_expiry()
設定 Session 的過期時間。您可以傳入不同的值
如果
value
為整數,Session 將在閒置這麼多秒後過期。例如,呼叫request.session.set_expiry(300)
會使 Session 在 5 分鐘後過期。如果
value
為datetime
或timedelta
物件,Session 將在該特定日期/時間過期。如果
value
為0
,使用者的 Session Cookie 將在使用者關閉網頁瀏覽器時過期。如果
value
為None
,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()
傳回
True
或False
,取決於使用者的 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 中儲存更進階的資料型別,包括 datetime
和 Decimal
,您需要編寫自訂的序列化器(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.session
的 flush()
方法。我們使用這個範例來示範如何使用 session 物件,而不是作為完整的 logout()
實作。
在視圖之外使用 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_REQUEST
為 True
,則會在每個請求上傳送 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.session
的 set_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
子類別都實作了以下資料操作方法
exists()
create()
save()
delete()
load()
這些方法透過 sync_to_async()
包裝後,提供非同步介面。如果可以使用非同步原生實作,則可以直接實作它們
aexists()
acreate()
asave()
adelete()
aload()
為了建立自訂 session 引擎或自訂現有的 session 引擎,您可以建立一個新的類別,繼承自 SessionBase
或任何其他現有的 SessionStore
類別。
您可以擴充 session 引擎,但是使用資料庫支援的 session 引擎進行擴充通常需要一些額外的努力(詳細資訊請參閱下一節)。
新增了 aexists()
、acreate()
、asave()
、adelete()
、aload()
和 aclear_expired()
方法。
擴充資料庫支援的 session 引擎¶
透過繼承 AbstractBaseSession
和 SessionStore
類別,可以建立一個基於 Django 內建的資料庫支援 session 引擎(即 db
和 cached_db
)的自訂資料庫支援 session 引擎。
AbstractBaseSession
和 BaseSessionManager
可從 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 的攻擊。