Authentication and browser caching in Django

While adding bits of authentication niceness to my website, I noticed a bit of ugliness. If I logged in, looked at a page that took account of the login, logged out, and hit Back in the browser, I still saw the logged-in page. That’s because the browser cached it, and just redisplayed on Back. I don’t care so much about caching non-authenticated views, but it just seems wrong to cache authenticated ones, so I have (I hope!) disabled it.

What disabling caching requires (here‘s a tutorial) is adding the directives Cache-Control:no-cache and Pragma:no-cache (different browsers may pay attention to one or the other!) to the html header, which is easily done. I have two methods for this; one is a replacement for render_to_response (which I was already using, to simplify using RequestContext), and the other is a wrapper for existing view functions, which can be used as a decorator. Code below.

Two important notes:

  • This should not be considered any sort of security fix.
  • I am not using the cache middleware; my site is way too small to need it. As far as I can tell this shouldn’t interact badly with the cache middleware, but sure don’t promise that.

Here’s the code:

def _add_to_header(response, key, value):
    if response.has_header(key):
        values = re.split(r'\s*,\s*', response[key])
        if not value in values:
            response[key] = ', '.join(values + [value])
    else:
        response[key] = value

def _nocache_if_auth(request, response):
    if request.user.is_authenticated():
        _add_to_header(response, 'Cache-Control', 'no-store')
        _add_to_header(response, 'Cache-Control', 'no-cache')
        _add_to_header(response, 'Pragma', 'no-store')
    return response

def rtr(request, *args, **kwargs):
    """
    If the request includes an authenticated user, disable browser caching.
    """
    response = render_to_response(
            context_instance=RequestContext(request),
            *args, **kwargs)
    return _nocache_if_auth(request, response)

def nocache_if_authenticated(fn):
    """
    Wrap the given view function so that browser caching is disabled
    with authenticated users.
    """
    def wrapped(request, *args, **kwargs):
        response = fn(request, *args, **kwargs)
        return _nocache_if_auth(request, response)
    return wrapped

UPDATE: D’oh! This should be middleware. I’ll implement that this weekend.

Advertisements

Tags: ,

One Response to “Authentication and browser caching in Django”

  1. Authentication and Browser Caching in Django, part II « Michael Lauer’s Weblog Says:

    […] and Browser Caching in Django, part II The other day I wrote about turning off browser caching when a user is logged in. Since I’m apparently a clueless […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: