middleware.py 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. import time
  2. from importlib import import_module
  3. from django.conf import settings
  4. from django.contrib.sessions.backends.base import UpdateError
  5. from django.contrib.sessions.exceptions import SessionInterrupted
  6. from django.utils.cache import patch_vary_headers
  7. from django.utils.deprecation import MiddlewareMixin
  8. from django.utils.http import http_date
  9. class SessionMiddleware(MiddlewareMixin):
  10. # RemovedInDjango40Warning: when the deprecation ends, replace with:
  11. # def __init__(self, get_response):
  12. def __init__(self, get_response=None):
  13. super().__init__(get_response)
  14. engine = import_module(settings.SESSION_ENGINE)
  15. self.SessionStore = engine.SessionStore
  16. def process_request(self, request):
  17. session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
  18. request.session = self.SessionStore(session_key)
  19. def process_response(self, request, response):
  20. """
  21. If request.session was modified, or if the configuration is to save the
  22. session every time, save the changes and set a session cookie or delete
  23. the session cookie if the session has been emptied.
  24. """
  25. try:
  26. accessed = request.session.accessed
  27. modified = request.session.modified
  28. empty = request.session.is_empty()
  29. except AttributeError:
  30. return response
  31. # First check if we need to delete this cookie.
  32. # The session should be deleted only if the session is entirely empty.
  33. if settings.SESSION_COOKIE_NAME in request.COOKIES and empty:
  34. response.delete_cookie(
  35. settings.SESSION_COOKIE_NAME,
  36. path=settings.SESSION_COOKIE_PATH,
  37. domain=settings.SESSION_COOKIE_DOMAIN,
  38. samesite=settings.SESSION_COOKIE_SAMESITE,
  39. )
  40. patch_vary_headers(response, ('Cookie',))
  41. else:
  42. if accessed:
  43. patch_vary_headers(response, ('Cookie',))
  44. if (modified or settings.SESSION_SAVE_EVERY_REQUEST) and not empty:
  45. if request.session.get_expire_at_browser_close():
  46. max_age = None
  47. expires = None
  48. else:
  49. max_age = request.session.get_expiry_age()
  50. expires_time = time.time() + max_age
  51. expires = http_date(expires_time)
  52. # Save the session data and refresh the client cookie.
  53. # Skip session save for 500 responses, refs #3881.
  54. if response.status_code != 500:
  55. try:
  56. request.session.save()
  57. except UpdateError:
  58. raise SessionInterrupted(
  59. "The request's session was deleted before the "
  60. "request completed. The user may have logged "
  61. "out in a concurrent request, for example."
  62. )
  63. response.set_cookie(
  64. settings.SESSION_COOKIE_NAME,
  65. request.session.session_key, max_age=max_age,
  66. expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
  67. path=settings.SESSION_COOKIE_PATH,
  68. secure=settings.SESSION_COOKIE_SECURE or None,
  69. httponly=settings.SESSION_COOKIE_HTTPONLY or None,
  70. samesite=settings.SESSION_COOKIE_SAMESITE,
  71. )
  72. return response