login_required decorator on ajax views to return 401 instead of 302

Go To StackoverFlow.com

13

While writing some views to respond to ajax requests i find it somewhat strange that the login_required decorator always returns a 302 status code for not authenticated users. As these views are ajax views, this seems somewhat inappropriate. I do not want the user to log in in such a case, but i want Django to tell the client that authentication is required to access such a view (a 401 should be the right status code, i think).

To achieve this, i started to write my own decorator login_required_ajax, but somehow this is beyond my skills. This is what i have come up with so far:

def login_required_ajax(function=None,redirect_field_name=None):
    """
    Just make sure the user is authenticated to access a certain ajax view

    Otherwise return a HttpResponse 401 - authentication required
    instead of the 302 redirect of the original Django decorator
    """
    def _decorator(view_func):
        def _wrapped_view(request, *args, **kwargs):
            if request.user.is_authenticated():
                return view_func(request, *args, **kwargs)
            else:
                return HttpResponse(status=401)

        if function is None:
            return _decorator
        else:
            return _decorator(function)

When using this decorator on a view, i get a ViewDoesNotExist exception as soon as i try to access any page on the site.

I first thought that the problem could be the direct return of an HttpResponse when a user is not authenticated, because a response object is not a callable. But then the decorator should work as long as i do not try to access the view in question, shouldn't it? And if this really is the crux, how can i write a decorator that returns a HttpResponse with a status code of 401?

2012-04-05 14:56
by marue
An idea that is not about your director: You could also introduce a middleware, which checks if a request is an ajax request and returns a 401 if it detects that the view returns a 302 for login... So you could keep using Django's decorator and handle ajax and normal requests different.. - Bernhard Vallant 2012-04-05 15:12
Does that really sound simpler to you than: "Create a custom decorator and use that on ajax views" ? ; - marue 2012-04-05 16:15


16

That's a pretty good attempt. Here's a couple of problems I spotted:

  1. Your _decorator function should return _wrapped_view.
  2. The indentation for your if function is None block is a bit off -- the login_required_ajax function needs to return the decorated function.

Here's the decorator with those changes made:

def login_required_ajax(function=None,redirect_field_name=None):
    """
    Just make sure the user is authenticated to access a certain ajax view

    Otherwise return a HttpResponse 401 - authentication required
    instead of the 302 redirect of the original Django decorator
    """
    def _decorator(view_func):
        def _wrapped_view(request, *args, **kwargs):
            if request.user.is_authenticated():
                return view_func(request, *args, **kwargs)
            else:
                return HttpResponse(status=401)
        return _wrapped_view

    if function is None:
        return _decorator
    else:
        return _decorator(function)
2012-04-05 15:10
by Alasdair
Works like a charm. Thank you - marue 2012-04-05 16:30
Ads