DEV Community

Serhat Teker
Serhat Teker

Posted on • Originally published at tech.serhatteker.com on

Django Login Middleware

Django provides a decorator called login_required that takes one of your views and prevents a user from seeing it unless they are authenticated. Every time we need to add this decorator above view. Usually it’s a real pain to use the login_required decorator all over the views of your sophisticated site. What if you forget to add it to view that contains sensitive information?

Django allows you to write custom middleware that gets access to each request so you can add functionality that can be applied to your whole site. My middleware simply intercepts each request and redirects users to the site login page, LOGIN_URL if they haven’t logged in. It also allows you to give of exceptions, i.e. pages that can be viewed without authenticated.

First create LoginRequiredMiddleware.py file:

import re

from django.conf import settings
from django.http import HttpResponseRedirect
from django.utils.deprecation import MiddlewareMixin
from django.utils.http import is_safe_url


EXEMPT_URLS = [re.compile(settings.LOGIN_URL.lstrip('/'))]
if hasattr(settings, 'LOGIN_EXEMPT_URLS'):
    EXEMPT_URLS += [re.compile(url) for url in settings.LOGIN_EXEMPT_URLS]


class LoginRequiredMiddleware(MiddlewareMixin):
    def process_request(self, request):
        assert hasattr(request, 'user'), "The Login Required Middleware"
        if not request.user.is_authenticated:
            path = request.path_info.lstrip('/')
            if not any(m.match(path) for m in EXEMPT_URLS):
                redirect_to = settings.LOGIN_URL
                # 'next' variable to support redirection to attempted page after login
                if len(path) > 0 and is_safe_url(
                    url=request.path_info, allowed_hosts=request.get_host()):
                    redirect_to = f"{settings.LOGIN_URL}?next={request.path_info}"

                return HttpResponseRedirect(redirect_to)

Enter fullscreen mode Exit fullscreen mode

Add this middleware in the core directory of your project. Such as:

└── project_root
    ├── manage.py
    ├── src
    │   ├── api
    │   ├── app
    │   └── core
    │   │   └── LoginRequiredMiddlware.py
    │   ├── static
    │   ├── templates
    │   └── users
    └── tests
        └── test_users.py
Enter fullscreen mode Exit fullscreen mode

Then add this middleware in your settings file, 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',
    # login middleware
    'src.core.middleware.LoginRequiredMiddleware',
]
Enter fullscreen mode Exit fullscreen mode

If you want to add other exception pages, pages that can be viewed without authentication, you can add those urls into LOGIN_EXEMPT_URLS in your settings:

LOGIN_EXEMPT_URLS = (
    r'^home/$',
    r'^register/$',
    r'^pricing/$',
)
Enter fullscreen mode Exit fullscreen mode

P.S: The LoginRequiredMiddleware requires authentication middleware to be installed. Edit your MIDDLEWARE setting to insert 'django.contrib.auth.middleware.AuthenticationMiddleware'. If that doesn't work, ensure your TEMPLATE_CONTEXT_PROCESSORS setting includes 'django.core.context_processors.auth'

For further details:
MIDDLEWARE and TEMPLATE_CONTEXT_PROCESSORS

Top comments (0)