Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the opposite of @login_required decorator for Django views?

If I want to make sure that a view is listed as having public access, is there a decorator equivalent to @public_access which would be the opposite of @login_required and make it clear that the view should be publicly accessible always?

One use case I have in mind is to automatically add "@csrf_exempt" to all public views in addition to making it clear in the code that the view should be publicly accessible.

like image 960
MikeN Avatar asked Feb 12 '10 18:02

MikeN


People also ask

What is @login_required in Django?

Django's login_required function is used to secure views in your web applications by forcing the client to authenticate with a valid logged-in User.

How to log a user out in Django?

To log out a user who has been logged in via django.contrib.auth.login() , use django.contrib.auth.logout() within your view. It takes an HttpRequest object and has no return value. Example: from django.contrib.auth import logout def logout_view(request): logout(request) # Redirect to a success page.


1 Answers

Unfortunately, there's currently no built-in support for this in Django, leaving you at risk of exposing sensitive info when @login_required is accidentally forgotten.

Here's a solution from one of my projects:

middleware/security.py:

def public(function):
    """
    Decorator for public views that do not require authentication
    """
    orig_func = function
    while isinstance(orig_func, partial):  # if partial - use original function for authorization
        orig_func = orig_func.func
    orig_func.is_public_view = True
    
    return function

def is_public(function):
    try:                                    # cache is found
        return function.is_public_view
    except AttributeError:                  # cache is not found
        result = function.__module__.startswith('django.') and not function.__module__.startswith('django.views.generic') # Avoid modifying admin and other built-in views
        
        try:                                # try to recreate cache
            function.is_public_view = result
        except AttributeError:
            pass
        
        return result


class NonpublicMiddleware(object):

    def process_view_check_logged(self, request, view_func, view_args, view_kwargs):
        return
    
    def process_view(self, request, view_func, view_args, view_kwargs):
        while isinstance(view_func, partial):  # if partial - use original function for authorization
            view_func = view_func.func

        request.public = is_public(view_func)
        if not is_public(view_func):
            if request.user.is_authenticated():     # only extended checks are needed
                return self.process_view_check_logged(request, view_func, view_args, view_kwargs)

            return self.redirect_to_login(request.get_full_path())  # => login page

    def redirect_to_login(self, original_target, login_url=settings.LOGIN_URL):
        return HttpResponseRedirect("%s?%s=%s" % (login_url, REDIRECT_FIELD_NAME, urlquote(original_target)))

settings.py:

MIDDLEWARE_CLASSES = (
    #...
    'middleware.security.NonpublicProfilefullMiddleware',
    #...
)

and, finally, view code:

from <projname>.middleware import publi

@public
def some_view(request):
    #...
    
# Login required is added automatically
def some_private_view(request):
    #...

Also, you may want to look at "Automatically decorating all views of a django project" blog post

like image 105
Alexander Lebedev Avatar answered Sep 22 '22 23:09

Alexander Lebedev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!