user_passes_test: raise exception if user does not pass

1.7k views Asked by At

I am trying to define a decorator to check if the user has admin certain privileges:

def admin_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None):
    actual_decorator = user_passes_test(
        lambda u: u.is_staff and u.is_authenticated() and not Association.objects.filter(admins=u).exists(),
        login_url=login_url,
        redirect_field_name=redirect_field_name
    )
    if function:
        return actual_decorator(function)
    return actual_decorator

The aim is to use this throught the views. Particularly, I am using it in a class-based view:

class MyCBV(CreateView):
    @method_decorator(admin_required)
    def dispatch(self, request, *args, **kwargs):
        return super(MyCBV, self).dispatch(request, *args, **kwargs)

The problem is that this view is loaded via AJAX, so the redirect doesn't happen. Also, the HTTP status the view returns is success even when the user authentication fails, so the client (JS) has no way of telling when the action really succeeded or not.

I usually have trouble understanding decorators and Django authentication, so my question is: how can I raise an exception (preferably the PermissionDenied exception) when the authentication decoration function fails?

1

There are 1 answers

2
Alasdair On

In Django 1.9+, you can use the UserPassesTestMixin instead of a decorator, and set raise_exception to True.

Since you are using Django 1.4, which is insecure and obsolete, you won't be able to do this. There isn't an option to make user_passes_test raise PermissionDenied rather than redirect. You could either try to detect the redirect in your JavaScript, or look at the user_passes_test source code and implement something similar that returns the response you want.