我正在考慮對我的應用程序使用相同的方法,我認爲它通常是安全的,但需要特別小心處理緩存一致性問題。
Django通常運行的方式是,當收到請求時,將針對會話表運行查詢以查找與請求中的cookie關聯的會話。然後,當您訪問request.user
時,將對用戶表運行查詢以查找給定會話的用戶(如果有的話,因爲Django支持匿名會話)。所以,默認情況下,Django需要兩個查詢來將每個請求與用戶關聯起來,這很昂貴。
關於Django會話的一個好處是,它可以在不擴展任何模型類的情況下用作關鍵值存儲區(與例如難以用附加字段擴展的User類相似)。所以你可以例如把request.session['email'] = user.email
在會話中存儲額外的數據。從某種意義上說,這是安全的,您從request.session
字典中讀取的內容肯定是您放在那裏的內容,客戶端無法更改這些值。所以你確實可以使用這種技術來避免查詢用戶表。爲避免查詢會話表,您需要啓用會話緩存(或將會話數據存儲在客戶端cookie中,因爲這樣的cookie被加密保護以防客戶端修改,因此這是安全的。
啓用緩存後,需要0個查詢才能將請求與用戶數據相關聯。但問題是緩存一致性。如果使用寫入直通選項(django.core.cache.backends.locmem.LocMemCache
和django.contrib.sessions.backends.cached_db
)在內存緩存中使用本地數據,會話數據將在每次修改時寫入數據庫,但如果數據庫存在於緩存中,將不會從數據庫讀取會話數據。如果你有多個Django進程,這會引發一個問題。如果一個進程修改會話(例如更改session['email']
),其他進程仍然可以使用舊的高速緩存值。
您可以使用共享緩存(Memcached後端)來解決此問題,這可以保證一個進程所做的更改對所有其他進程都可見。通過這種方式,您可以使用對Memcached後端的請求替換對Session表的查詢,該查詢應該快得多。
將會話數據存儲在客戶端cookie中也可以解決緩存一致性問題。如果您修改cookie中的電子郵件字段,則客戶發送的所有未來請求都應該有新的電子郵件。儘管客戶可以故意發送一箇舊的cookie,但仍舊保留舊的值。這是否是一個問題是應用程序依賴。
哇,非常好/徹底的答案,謝謝。爲你+1。我當然想在生產中使用memcached;對於開發來說,使用本地用戶的本地服務器,使用本地內存緩存就足夠了,對吧? (因爲在這種情況下只有一個Django進程) –
還有一個問題 - 如果我只是想在會話中存儲對應於登錄用戶的整個User模型*,那麼這樣做還是需要的首先序列化它? –
@PlatinumAzure在Django開發服務器的情況下,本地緩存應該足夠了。當您使用具有多個工作者的服務器時(例如帶-w參數的gunicorn),會出現問題。我已經檢查過把用戶對象放在會話字典中是行得通的,但不是你可能需要的方式。用戶被正確序列化和反序列化,但在訪問時,查詢是針對用戶表運行的,因此緩存的好處將丟失。對於我的應用程序,我計劃手動將用戶對象中的所有相關字段複製並更新到會話字典。 –