Django

Code

Ticket #395 (closed: fixed)

Opened 3 years ago

Last modified 2 years ago

[patch] New session middleware for browser-session length cookies

Reported by: rob@contrastsweb.com Assigned to: adrian
Milestone: Component: Core framework
Version: Keywords:
Cc: Triage Stage: Unreviewed
Has patch: 1 Needs documentation: 0
Needs tests: 0 Patch needs improvement: 0

Description

I noticed that the SessionsMiddleware class was setting a cookie with an explicit expiration date. So I created this modified middleware for my application that allows SESSION_COOKIE_AGE to be set to None (which then creates a session cookie with no expiration date, meaning the cookie will be deleted when the browser session ends).

Currently the middleware sets the session expiration date in the database to 1 hour from when the session cookie is set, but this could be changed with a configuration variable (SESSION_EXPIRATION_AGE, perhaps?).

from django.middleware import sessions as sessionsMiddleware
from django.conf.settings import SESSION_COOKIE_NAME, SESSION_COOKIE_AGE, SESSION_COOKIE_DOMAIN
from django.models.core import sessions
import datetime

class SingleSessionMiddleware(sessionsMiddleware.SessionMiddleware):
  def process_response(self, request, response):
    try:
      modified = request.session.modified
    except AttributeError:
      modified = False
    if modified:
      session_key = request.session.session_key or sessions.get_new_session_key()
      if SESSION_COOKIE_AGE != None:
        new_session = sessions.save(session_key, request.session._session,
          datetime.datetime.now() + datetime.timedelta(seconds=SESSION_COOKIE_AGE))
      else:
        # right now I'm just making sessions last for an hour ... should
        # probably make a configuration directive to specify the seconds
        # till the session expires
        new_session = sessions.save(session_key, request.session._session, 
          datetime.datetime.now() + datetime.timedelta(hours=1))
    
      # TODO: Accept variable session length and domain.
      response.set_cookie(SESSION_COOKIE_NAME, session_key,
        max_age=SESSION_COOKIE_AGE, domain=SESSION_COOKIE_DOMAIN)
    return response

Attachments

Change History

08/23/05 20:33:45 changed by rob@contrastsweb.com

I just noticed one downside to this code (assuming you set SESSION_COOKIE_AGE=None in settings/main.py): the admin still uses the basic django session code which doesn't like None...

Traceback (most recent call last):

  File "/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/django/core/servers/basehttp.py", line 272, in run
    self.result = application(self.environ, self.start_response)

  File "/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/django/core/servers/basehttp.py", line 615, in __call__
    return self.application(environ, start_response)

  File "/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/django/core/handlers/wsgi.py", line 121, in __call__
    response = middleware_method(request, response)

  File "/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/django/middleware/sessions.py", line 68, in process_response
    datetime.datetime.now() + datetime.timedelta(seconds=SESSION_COOKIE_AGE))

TypeError: unsupported type for timedelta seconds component: NoneType

Placing SESSION_COOKIE_AGE=60 * 60 * 24 * 7 * 2 in the settings/admin.py fixes the problem, but I thought this was an appropriate issue to add to the ticket.

09/22/05 20:22:19 changed by adrian

  • status changed from new to assigned.

04/30/06 00:03:32 changed by b dot nuttall at vanderbilt.edu

So I got this working with the lastest Django SVN. Here's the middleware class I used:

from django.conf.settings import SESSION_COOKIE_NAME, SESSION_COOKIE_AGE, SESSION_COOKIE_DOMAIN, SESSION_SAVE_EVERY_REQUEST
from django.models.core import sessions
from django.utils.cache import patch_vary_headers
from django.middleware import sessions as sessionsMiddleware

import datetime

class SingleSessionMiddleware(sessionsMiddleware.SessionMiddleware):
    def process_response(self, request, response):
        # If request.session was modified, or if response.session was set, save
        # those changes and set a session cookie.
        patch_vary_headers(response, ('Cookie',))
        try:
            modified = request.session.modified
        except AttributeError:
            pass
        else:
            if modified or SESSION_SAVE_EVERY_REQUEST:
                session_key = request.session.session_key or sessions.get_new_session_key()
                if SESSION_COOKIE_AGE != None:
                    new_session = sessions.save(session_key, request.session._session, datetime.datetime.now() + datetime.timedelta(seconds=SESSION_COOKIE_AGE))
                    expires = datetime.datetime.strftime(datetime.datetime.utcnow() + datetime.timedelta(seconds=SESSION_COOKIE_AGE), "%a, %d-%b-%Y %H:%M:%S GMT")
                    response.set_cookie(SESSION_COOKIE_NAME, session_key, max_age=SESSION_COOKIE_AGE, expires=expires, domain=SESSION_COOKIE_DOMAIN)
                else:
                    new_session = sessions.save(session_key, request.session._session, datetime.datetime.now() + datetime.timedelta(hours=1))
                    response.set_cookie(SESSION_COOKIE_NAME, session_key, max_age=SESSION_COOKIE_AGE, domain=SESSION_COOKIE_DOMAIN)  
        return response

06/01/06 17:25:08 changed by adrian

  • status changed from assigned to closed.
  • resolution set to fixed.

(In [3049]) Fixed #395 -- Added SESSION_EXPIRE_AT_BROWSER_CLOSE setting, which regulates whether session framework should use browser-session-length cookies.

06/06/06 22:41:05 changed by anonymous

  • priority changed from normal to highest.
  • type changed from enhancement to defect.
  • severity changed from normal to blocker.

Add/Change #395 ([patch] New session middleware for browser-session length cookies)




Change Properties
Action