Django Caching Middleware & Login Page

June 2nd, 2008  |  Published in Django, StartupIndex, Web Development  |  2 Comments

Recently on StartupIndex.ca, I’ve noticed a problem where the first time you login it fails, the second time it works. I sat down last night, and spent some time attempting to solve this problem. My search on the greater web didn’t end up with very many results, I did find one mailing list thread on “django.contrib.auth.views.login failing cookie test“. This wasn’t exactly what I was looking for, but it set me down the right path.

Django comes with a caching middleware that caches any request made to the site that doesn’t have a POST or GET. You can set the cache to only cache pages for anonymous (using CACHE_MIDDLEWARE_ANONYMOUS_ONLY). The second piece of the puzzle is that the login view for Django sets a test cookie when a visitor first comes to the page, if this is not there, the login will fail.

What happens is:

  1. Make a request to the login page without any GET or POST parameters.
  2. Web server returns the cached page. (Note: this doesn’t set the cookie because no Python code has been run, the page returned is static)
  3. The user enters in the login information and submits the information. This is sent to the server as a POST.
  4. The server, because of the POST, now runs the login view. This fails because there was no cookie previously set, but it does set the cookie that should have been previously set.
  5. The error message shown to the user is as if it was a failed attempt. If the user reenters the information, the login will now work as the cookie is now set.

Hopefully that makes some sense.

What is the solution? Unfortunately, the caching middleware doesn’t allow you to fine-grain what it caches, it’s an all or nothing. There are two solutions:

  1. Always pass a GET param to the login page. By passing a GET param, the caching middleware will not return the cached page.
  2. Turn off the caching middleware and instead use the more fine-grained per-view cache.

I’m trying the GET parameter. We’ll see how it works.

Responses

  1. SmileyChris says:

    June 3rd, 2008 at 2:19 pm (#)

    It looks like you need to open a ticket.

    Since recently, the caching also respects setting a custom max-age header, the contrib.auth login view could just use the decorator @cache_control(max_age=0)
    (as explained in http://www.djangoproject.com/documentation/cache/#controlling-cache-using-other-headers)

  2. clong says:

    June 4th, 2008 at 1:44 pm (#)

    Hey SmileyChris,

    Thanks for pointing that out. I just opened up a ticket for it: http://code.djangoproject.com/ticket/7364

    I did up a quick diff for the ticket, I ended up using the @never_cache decorator. I put the changes live on StartupIndex.ca, and it seems to be working.

Leave a Response

Subscribe via RSS

If you like the content of this website and are looking for a way to be notified of new content, look no further. Just click the orange icon to your right and subscribe using your favorite feed reader.




You can trust BuyResearchPaper when using its paper writing service. | Spend money wisely. Buy essay only at AnyEssays.com. | sildenafil citrate