views:

484

answers:

4

Suppose someone is editing a HTML form, and their session times out, how can one have Django re-authenticate that individual without losing the content the user had entered into the form?

The snippet Django Snippets: Require login across entire site suggests how to do site-wide authentication, but I expect it will lose the GET component of the string (namely because request.path does not include it), and definitely lose the POST data.

How can one preserve the POST and GET across those inconvenient timeouts. I find that finessed web-sites tend to handle this intelligently, and I'd like to be able to do it in Django (as would others, I imagine!).

Thoughts would be appreciated. Thank you.

+2  A: 

Add onsubmit handler to all your forms that would check session via JS and prompt use to login before proceeding. This way form submit would not really happen before user is logged in again.

And make sure you verify that logged in user stays the same across sessions.

Alex Lebedev
+2  A: 

It is not exactly Django-specific but HTTP (The Stateless) specific... In the case system ends in issuing Redirect while handling POST (switching to GET from original POST) and risking loosing data one should store the data somewhere (db, memcached, etc.) and make the key under which they are stored be carried through authentication (or other) process.

The simplest is Cookie as requires zero-care about the key. The more difficult but more bullet-proof (against read-oly Cookie jars) is key in URL user is redirected to and consecutive relay from request to request (like SESSION in solution from almost decade ago).

Upon finishing the authentication (or other process) data (and process interrupted) can be picked from datastore by the key passed (either from Cookies, or from GET request variable).

myroslav
+3  A: 

I have two suggestions.

Redirect/Middleware

Since you're already using middleware to handle the login requirement, you could modify this middleware. Or possibly, create another middleware class that is called after the login middleware. These ideas are intertwined so it may make more sense to modify the existing one.

  1. If not logged in, capture the GET and POST data in the middleware, and store it in the session
  2. If the user is authenticated, check for the value(s) set in #1. If they exist, modify request.GET and request.POST to reflect it, and delete the session data.

I think this should work cleanly, and many people would find it useful. It'd be a great post on djangosnippets.org.

Ajax technique

This is less practical if you already have your form handling in place, but could create a better user experience. If you POST asynchronously, your Javascript handler could recognize a "login required" response code, and then display a popup dialog requesting login. On completion, the user could resubmit the form.

Daniel
A: 

I don't like sessions in general, though I suppose with an authenticated site you are already using them so maybe the answers above fit into your approach.

Without sessions, I'd do something similar to Daniels answer, i.e. catch the original POST/GET in the middleware, but I'd change the redirect to include the posted info.

This is easier on GETs and normally is just the full GETstring encoded in a redirect component of the login url.

For POSTs you can either convert to the get method which works fine for smaller forms but for bigger forms that would make the url too long, I'd do a rePOST, posting the data to a login form possibly encoded and storing it in a single hidden (almost like a .net viewstate actually)

Doing this in django is tricky as you can't do a redirect, so I'd use the middleware to manually call the login view, and write to HttpResponse from there. EDIT After some more looking into this, apparently the magic admin side fo django has something similar already implemented, as found by Jerry Stratton

Looks like a good option. I'll try it out and feedback.

RonaldHobbs