kender kender - 3 months ago 27
Javascript Question

Django authentication and Ajax - URLs that require login

I want to add some Ajax-niceness to my Django-coded website.

In my Django code, I use the

@login_required
decorator from
django.contrib.auth.decorators
to mark which view requires authentication. The default behavior when a not authenticated user clicks it is to redirect him/her to login page, and then pass the target page.

What I saw on some sites, and really liked, is that when user clicks a link leading to a place restricted to logged-only users, instead of getting redirected to a login page, he/she gets a popup window (via JavaScript) asking him/her to log in or register. There's no redirection part, so no need for a user to use the "back" key if he/she decides he/she really doesn't like the website enough to waste the time registering.

So, the qestion is: how would you manage the task of automatically marking some links as "restricted" so JavaScript can handle their
onclick
event and display a "please log in" popup?

Answer

I am facing the same issue, and, like you, I would like a simple decorator to wrap around a Django ajax view in order to handle authentication in the same way that I have other views. One approach that seems promising to me is to use such a decorator in conjunction with JavaScript that looks for a certain value in the response.

Here is first revised draft of the decorator:

from functools import wraps

def ajax_login_required(view_func):
    @wraps(view_func)
    def wrapper(request, *args, **kwargs):
        if request.user.is_authenticated():
            return view_func(request, *args, **kwargs)
        json = simplejson.dumps({ 'not_authenticated': True })
        return HttpResponse(json, mimetype='application/json')
    return wrapper

Here is the view:

@ajax_login_required
def ajax_update_module(request, module_slug, action):
    # Etc ...
    return HttpResponse(json, mimetype='application/json')

And here is the JavaScript (jQuery):

$.post('/restricted-url/', data, function(json) {
    if (json.not_authenticated) {
        alert('Not authorized.');  // Or something in a message DIV
        return;
    }
    // Etc ...
});

EDIT: I've attempted to use functools.wraps, as suggested. I have not actually used this decorator in working code, so beware of possible bugs.