diff --git a/django/contrib/sessions/backends/base.py b/django/contrib/sessions/backends/base.py index 0e8ade3fbc..453f533e90 100644 --- a/django/contrib/sessions/backends/base.py +++ b/django/contrib/sessions/backends/base.py @@ -206,6 +206,9 @@ class SessionBase: _session = property(_get_session) + def get_session_cookie_age(self): + return settings.SESSION_COOKIE_AGE + def get_expiry_age(self, **kwargs): """Get the number of seconds until the session expires. @@ -225,7 +228,7 @@ class SessionBase: expiry = self.get('_session_expiry') if not expiry: # Checks both None and 0 cases - return settings.SESSION_COOKIE_AGE + return self.get_session_cookie_age() if not isinstance(expiry, datetime): return expiry delta = expiry - modification @@ -249,7 +252,7 @@ class SessionBase: if isinstance(expiry, datetime): return expiry - expiry = expiry or settings.SESSION_COOKIE_AGE # Checks both None and 0 cases + expiry = expiry or self.get_session_cookie_age() return modification + timedelta(seconds=expiry) def set_expiry(self, value): diff --git a/django/contrib/sessions/backends/file.py b/django/contrib/sessions/backends/file.py index e75195f222..cc5f93a8ff 100644 --- a/django/contrib/sessions/backends/file.py +++ b/django/contrib/sessions/backends/file.py @@ -69,7 +69,7 @@ class SessionStore(SessionBase): Return the expiry time of the file storing the session's content. """ return session_data.get('_session_expiry') or ( - self._last_modification() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE) + self._last_modification() + datetime.timedelta(seconds=self.get_session_cookie_age()) ) def load(self): diff --git a/django/contrib/sessions/backends/signed_cookies.py b/django/contrib/sessions/backends/signed_cookies.py index 1ee7790b8e..8942df1ea4 100644 --- a/django/contrib/sessions/backends/signed_cookies.py +++ b/django/contrib/sessions/backends/signed_cookies.py @@ -1,4 +1,3 @@ -from django.conf import settings from django.contrib.sessions.backends.base import SessionBase from django.core import signing @@ -16,7 +15,7 @@ class SessionStore(SessionBase): self.session_key, serializer=self.serializer, # This doesn't handle non-default expiry dates, see #19201 - max_age=settings.SESSION_COOKIE_AGE, + max_age=self.get_session_cookie_age(), salt='django.contrib.sessions.backends.signed_cookies', ) except Exception: diff --git a/docs/releases/3.0.txt b/docs/releases/3.0.txt index d98a4718cd..ac275b31b9 100644 --- a/docs/releases/3.0.txt +++ b/docs/releases/3.0.txt @@ -96,7 +96,9 @@ Minor features :mod:`django.contrib.sessions` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* ... +* The new + :meth:`~django.contrib.sessions.backends.base.SessionBase.get_session_cookie_age()` + methods allows dynamically specifying the session cookie age. :mod:`django.contrib.sitemaps` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/topics/http/sessions.txt b/docs/topics/http/sessions.txt index 745c735e46..313f33bfb9 100644 --- a/docs/topics/http/sessions.txt +++ b/docs/topics/http/sessions.txt @@ -244,6 +244,13 @@ You can edit it multiple times. Deletes the test cookie. Use this to clean up after yourself. + .. method:: get_session_cookie_age() + + .. versionadded:: 3.0 + + Returns the age of session cookies, in seconds. Defaults to + :setting:`SESSION_COOKIE_AGE`. + .. method:: set_expiry(value) Sets the expiration time for the session. You can pass a number of diff --git a/tests/sessions_tests/models.py b/tests/sessions_tests/models.py index 4fa216d9e6..557dbf7865 100644 --- a/tests/sessions_tests/models.py +++ b/tests/sessions_tests/models.py @@ -38,3 +38,6 @@ class SessionStore(DBStore): obj.account_id = account_id return obj + + def get_session_cookie_age(self): + return 60 * 60 * 24 # One day. diff --git a/tests/sessions_tests/tests.py b/tests/sessions_tests/tests.py index e9896dc18a..24e4e0c81b 100644 --- a/tests/sessions_tests/tests.py +++ b/tests/sessions_tests/tests.py @@ -454,6 +454,7 @@ class DatabaseSessionWithTimeZoneTests(DatabaseSessionTests): class CustomDatabaseSessionTests(DatabaseSessionTests): backend = CustomDatabaseSession session_engine = 'sessions_tests.models' + custom_session_cookie_age = 60 * 60 * 24 # One day. def test_extra_session_field(self): # Set the account ID to be picked up by a custom session storage @@ -473,6 +474,17 @@ class CustomDatabaseSessionTests(DatabaseSessionTests): s = self.model.objects.get(session_key=self.session.session_key) self.assertIsNone(s.account_id) + def test_custom_expiry_reset(self): + self.session.set_expiry(None) + self.session.set_expiry(10) + self.session.set_expiry(None) + self.assertEqual(self.session.get_expiry_age(), self.custom_session_cookie_age) + + def test_default_expiry(self): + self.assertEqual(self.session.get_expiry_age(), self.custom_session_cookie_age) + self.session.set_expiry(0) + self.assertEqual(self.session.get_expiry_age(), self.custom_session_cookie_age) + class CacheDBSessionTests(SessionTestsMixin, TestCase):