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

后端 未结 6 2067
耶瑟儿~
耶瑟儿~ 2020-12-29 09:37

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 ma

6条回答
  •  一个人的身影
    2020-12-29 09:48

    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 .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

提交回复
热议问题