#395 closed defect (fixed)
[patch] New session middleware for browser-session length cookies
| Reported by: | Owned by: | Adrian Holovaty | |
|---|---|---|---|
| Component: | Core (Other) | Version: | |
| Severity: | blocker | Keywords: | |
| Cc: | Triage Stage: | Unreviewed | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
I noticed that the [source:/django/trunk/django/middleware/sessions.py 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
Change History (5)
comment:1 by , 20 years ago
comment:2 by , 20 years ago
| Status: | new → assigned |
|---|
comment:3 by , 20 years ago
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
comment:4 by , 19 years ago
| Resolution: | → fixed |
|---|---|
| Status: | assigned → closed |
comment:5 by , 19 years ago
| priority: | normal → highest |
|---|---|
| Severity: | normal → blocker |
| Type: | enhancement → defect |
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: NoneTypePlacing
SESSION_COOKIE_AGE=60 * 60 * 24 * 7 * 2in the settings/admin.py fixes the problem, but I thought this was an appropriate issue to add to the ticket.