loading...

Django Login Middleware

serhatteker profile image Serhat Teker Originally published at tech.serhatteker.com on ・2 min read

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)

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

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',
]

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/$',
)

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

Discussion

pic
Editor guide