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.