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

29👍

Dropped this into a middleware.py file in my project root (taken from http://onecreativeblog.com/post/59051248/django-login-required-middleware)

from django.http import HttpResponseRedirect
from django.conf import settings
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:
    """
    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).

    Requires authentication middleware and template context processors to be
    loaded. You'll get an error if they aren't.
    """
    def process_request(self, request):
        assert hasattr(request, 'user'), "The Login Required middleware\
 requires authentication middleware to be installed. Edit your\
 MIDDLEWARE_CLASSES setting to insert\
 'django.contrib.auth.middlware.AuthenticationMiddleware'. If that doesn't\
 work, ensure your TEMPLATE_CONTEXT_PROCESSORS setting includes\
 'django.core.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)

Then appended projectname.middleware.LoginRequiredMiddleware to my MIDDLEWARE_CLASSES in settings.py.

14👍

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

10👍

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.

9👍

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'
👤dKen

3👍

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).
👤mehmet

2👍

Use middleware.

http://www.djangobook.com/en/2.0/chapter17/
and
http://docs.djangoproject.com/en/1.2/topics/http/middleware/#topics-http-middleware

I’m assuming this didn’t change a whole lot in 1.2

Middleware allows you to create a class with methods who will process every request at various times/conditions, as you define.

for example process_request(request) would fire before your view, and you can force authentication and authorization at this point.

0👍

In addition to meder omuraliev answer if you want exempt url like this (with regexp):

url(r'^my/url/(?P<pk>[0-9]+)/$', views.my_view, name='my_url')

add it to EXEMPT_URLS list like this:

LOGIN_EXEMPT_URLS = [r'^my/url/([0-9]+)/$']

r’..’ in the beginning of the string necessary.

👤magrif

0👍

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’

👤user99

0👍

If you have lots of views and you do not want to touch any one you can just use Middleware for this issue. Try code below:


import traceback
from django.contrib.auth.decorators import login_required


class RejectAnonymousUsersMiddleware(object):

    def process_view(self, request, view_func, view_args, view_kwargs):
        current_route_name = resolve(request.path_info).url_name

        if current_route_name in settings.AUTH_EXEMPT_ROUTES:
            return

        if  request.user.is_authenticated:
            return

        return login_required(view_func)(request, *view_args, **view_kwargs)

Cautions:

  • You must add this middleware to the bottommost of middleware section
    of settings.py
  • You should put this variable in settings.py
    • AUTH_EXEMPT_ROUTES = (‘register’, ‘login’, ‘forgot-password’)

0👍

Thanks from @Ehsan Ahmadi

In the newer version of Django, the middleware should be written like this( my Djang version = 4.1.1) :

middleware.py

from django.contrib.auth.decorators import login_required
from django.urls import resolve
from django.utils.deprecation import MiddlewareMixin

AUTH_EXEMPT_ROUTES = ('captcha-image', 'login', 'captcha')

class RejectAnonymousUsersMiddleware(MiddlewareMixin):

    def process_view(self, request, view_func, view_args, view_kwargs):
        current_route_name = resolve(request.path_info).url_name

        if  request.user.is_authenticated:
            return

        if current_route_name in AUTH_EXEMPT_ROUTES:
            return


        return login_required(view_func)(request, *view_args, **view_kwargs)

settings.py

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'myproject.middleware.RejectAnonymousUsersMiddleware',  

]
👤henrry

-1👍

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.

Leave a comment