Django: How can I apply the login_required decorator to my entire site (excluding static media)?

前端 未结 10 1998
日久生厌
日久生厌 2020-12-24 07:21

The example provides a snippet for an application level view, but what if I have lots of different (and some non-application) entries in my \"urls.py\" file, including templ

相关标签:
10条回答
  • 2020-12-24 07:46

    Some of the previous answers are either outdated (older version of Django), or introduce poor programming practices (hardcoding URLs, not using routes). Here's my take that is more DRY and sustainable/maintainable (adapted from Mehmet's answer above).

    To highlight the improvements here, this relies on giving URLs route names (which are much more reliable than using hard-coded URLs/URIs that change and have trailing/leading slashes).

    from django.utils.deprecation import MiddlewareMixin
    from django.urls import resolve, reverse
    from django.http import HttpResponseRedirect
    from my_project import settings
    
    class LoginRequiredMiddleware(MiddlewareMixin):
        """
        Middleware that requires a user to be authenticated to view any page other
        than LOGIN_URL. Exemptions to this requirement can optionally be specified
        in settings by setting a tuple of routes to ignore
        """
        def process_request(self, request):
            assert hasattr(request, 'user'), """
            The Login Required middleware needs to be after AuthenticationMiddleware.
            Also make sure to include the template context_processor:
            'django.contrib.auth.context_processors.auth'."""
    
            if not request.user.is_authenticated:
                current_route_name = resolve(request.path_info).url_name
    
                if not current_route_name in settings.AUTH_EXEMPT_ROUTES:
                    return HttpResponseRedirect(reverse(settings.AUTH_LOGIN_ROUTE))
    

    And in the settings.py file, you can define the following:

    AUTH_EXEMPT_ROUTES = ('register', 'login', 'forgot-password')
    AUTH_LOGIN_ROUTE = 'register'
    
    0 讨论(0)
  • 2020-12-24 07:47

    Here is the classical LoginRequiredMiddleware for Django 1.10+:

    from django.utils.deprecation import MiddlewareMixin
    
    class LoginRequiredMiddleware(MiddlewareMixin):
        """
        Middleware that requires a user to be authenticated to view any page other
        than LOGIN_URL. Exemptions to this requirement can optionally be specified
        in settings via a list of regular expressions in LOGIN_EXEMPT_URLS (which
        you can copy from your urls.py).
        """
        def process_request(self, request):
            assert hasattr(request, 'user'), """
            The Login Required middleware needs to be after AuthenticationMiddleware.
            Also make sure to include the template context_processor:
            'django.contrib.auth.context_processors.auth'."""
            if not request.user.is_authenticated:
                path = request.path_info.lstrip('/')
                if not any(m.match(path) for m in EXEMPT_URLS):
                    return HttpResponseRedirect(settings.LOGIN_URL)
    

    Noteworthy differences:

    • path.to.LoginRequiredMiddleware should be included in MIDDLEWARE not MIDDLEWARE_CLASSES in settings.py.
    • is_authenticated is a bool not a method.
    • see the docs for more info (although some parts are not very clear).
    0 讨论(0)
  • 2020-12-24 07:51

    Here's a slightly shorter middleware.

    from django.contrib.auth.decorators import login_required
    
    class LoginRequiredMiddleware(object):
        def process_view(self, request, view_func, view_args, view_kwargs):
            if not getattr(view_func, 'login_required', True):
                return None
            return login_required(view_func)(request, *view_args, **view_kwargs)
    

    You'll have to set "login_required" to False on each view you don't need to be logged in to see:

    Function-views:

    def someview(request, *args, **kwargs):
        # body of view
    someview.login_required = False
    

    Class-based views:

    class SomeView(View):
        login_required = False
        # body of view
    
    #or
    
    class SomeView(View):
        # body of view
    someview = SomeView.as_view()
    someview.login_required = False
    

    This means you'll have to do something about the login-views, but I always end up writing my own auth-backend anyway.

    0 讨论(0)
  • 2020-12-24 07:57

    For those who have come by later to this, you might find that django-stronghold fits your usecase well. You whitelist any urls you want to be public, the rest are login required.

    https://github.com/mgrouchy/django-stronghold

    0 讨论(0)
  • 2020-12-24 07:57

    Here's an example for new-style middleware in Django 1.10+:

    from django.contrib.auth.decorators import login_required
    from django.urls import reverse
    
    def login_required_middleware(get_response):
        """
            Require user to be logged in for all views. 
        """
        exceptions = {'/admin/login/'}
        def middleware(request):
            if request.path in exceptions:
                return get_response(request)
            return login_required(get_response, login_url=reverse('admin:login'))(request)
        return middleware
    

    This example exempts the admin login form to avoid redirect loop, and uses that form as the login url.

    0 讨论(0)
  • 2020-12-24 07:58

    Django Login Required Middleware

    Put this code in middleware.py :

    from django.http import HttpResponseRedirect
    from django.conf import settings
    from django.utils.deprecation import MiddlewareMixin
    from re import compile
    
    EXEMPT_URLS = [compile(settings.LOGIN_URL.lstrip('/'))]
    if hasattr(settings, 'LOGIN_EXEMPT_URLS'):
        EXEMPT_URLS += [compile(expr) for expr in settings.LOGIN_EXEMPT_URLS]
    
    class LoginRequiredMiddleware(MiddlewareMixin):
        def process_request(self, request):
            assert hasattr(request, 'user')
            if not request.user.is_authenticated:
                path = request.path_info.lstrip('/')
                if not any(m.match(path) for m in EXEMPT_URLS):
                    return HttpResponseRedirect(settings.LOGIN_URL)
    

    And, in settings.py :

    LOGIN_URL = '/app_name/login'
    
    LOGIN_EXEMPT_URLS=(
        r'/app_name/login/',
    )
    
    MIDDLEWARE_CLASSES = (
        # ...
        'python.path.to.LoginRequiredMiddleware',
    )
    

    Like this : 'app_name.middleware.LoginRequiredMiddleware'

    0 讨论(0)
提交回复
热议问题