mirror of
https://github.com/django/django.git
synced 2025-03-29 02:30:48 +00:00
Previously, when logging out, the existing session was overwritten by a new sessionid instead of deleting the session altogether. This behavior added overhead by creating a new session record in whichever backend was in use: db, cache, etc. This extra session is unnecessary at the time since no session data is meant to be preserved when explicitly logging out.
87 lines
2.8 KiB
Python
87 lines
2.8 KiB
Python
"""
|
|
Cached, database-backed sessions.
|
|
"""
|
|
|
|
import logging
|
|
|
|
from django.conf import settings
|
|
from django.contrib.sessions.backends.db import SessionStore as DBStore
|
|
from django.core.cache import caches
|
|
from django.core.exceptions import SuspiciousOperation
|
|
from django.utils import timezone
|
|
from django.utils.encoding import force_text
|
|
|
|
KEY_PREFIX = "django.contrib.sessions.cached_db"
|
|
|
|
|
|
class SessionStore(DBStore):
|
|
"""
|
|
Implements cached, database backed sessions.
|
|
"""
|
|
|
|
def __init__(self, session_key=None):
|
|
self._cache = caches[settings.SESSION_CACHE_ALIAS]
|
|
super(SessionStore, self).__init__(session_key)
|
|
|
|
@property
|
|
def cache_key(self):
|
|
return KEY_PREFIX + self._get_or_create_session_key()
|
|
|
|
def load(self):
|
|
try:
|
|
data = self._cache.get(self.cache_key, None)
|
|
except Exception:
|
|
# Some backends (e.g. memcache) raise an exception on invalid
|
|
# cache keys. If this happens, reset the session. See #17810.
|
|
data = None
|
|
|
|
if data is None:
|
|
# Duplicate DBStore.load, because we need to keep track
|
|
# of the expiry date to set it properly in the cache.
|
|
try:
|
|
s = Session.objects.get(
|
|
session_key=self.session_key,
|
|
expire_date__gt=timezone.now()
|
|
)
|
|
data = self.decode(s.session_data)
|
|
self._cache.set(self.cache_key, data,
|
|
self.get_expiry_age(expiry=s.expire_date))
|
|
except (Session.DoesNotExist, SuspiciousOperation) as e:
|
|
if isinstance(e, SuspiciousOperation):
|
|
logger = logging.getLogger('django.security.%s' %
|
|
e.__class__.__name__)
|
|
logger.warning(force_text(e))
|
|
self.create()
|
|
data = {}
|
|
return data
|
|
|
|
def exists(self, session_key):
|
|
if (KEY_PREFIX + session_key) in self._cache:
|
|
return True
|
|
return super(SessionStore, self).exists(session_key)
|
|
|
|
def save(self, must_create=False):
|
|
super(SessionStore, self).save(must_create)
|
|
self._cache.set(self.cache_key, self._session, self.get_expiry_age())
|
|
|
|
def delete(self, session_key=None):
|
|
super(SessionStore, self).delete(session_key)
|
|
if session_key is None:
|
|
if self.session_key is None:
|
|
return
|
|
session_key = self.session_key
|
|
self._cache.delete(KEY_PREFIX + session_key)
|
|
|
|
def flush(self):
|
|
"""
|
|
Removes the current session data from the database and regenerates the
|
|
key.
|
|
"""
|
|
self.clear()
|
|
self.delete(self.session_key)
|
|
self._session_key = ''
|
|
|
|
|
|
# At bottom to avoid circular import
|
|
from django.contrib.sessions.models import Session
|