Ограничение входа в Django Admin по IP-адресу (middleware)

В дополнение к аутентификации и авторизации, когда доступ к панели администратора предоставляется на основе учётных данных пользователя, для повышения уровня безопасности полезно настраивать контроль доступа. В некоторых случах удобны блокировка/разрешение доступа на основе списка доверенных IP/подсетей.

Разместите код в файле, например, middleware.py:

from django.conf import settings
from django.core.exceptions import PermissionDenied
from django.urls import resolve
from netaddr import IPAddress, IPSet


def get_remote_addr(request):
    return request.META['REMOTE_ADDR']


def get_ipaddr(request):
    return IPAddress(get_remote_addr(request))


def get_ipset_from_settings(name):
    return IPSet(getattr(settings, name, []))


class AdminWhitelistMiddleware:
    """Limits login to specific IP's in Django 3"""

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        current_url = resolve(request.path_info)
        is_admin_app = (current_url.app_name == 'admin')
        whitelist = get_ipset_from_settings('ADMIN_WHITELIST')
        if is_admin_app and not get_ipaddr(request) in whitelist:
            raise PermissionDenied
        return self.get_response(request)

Подключите AdminWhitelistMiddleware в модуле настроек Django:

MIDDLEWARE = [
    'core.middleware.AdminWhitelistMiddleware',
    ...
]

Определите список доверенных IP-адресов и подсетей:

ADMIN_WHITELIST = [ '127.0.0.1', '172.20.0.0/24', … ]

Поддержка X-Forwarded-For

Для получия IP-адреса клиента, подключающегося к веб-серверу через HTTP-прокси или балансировщик нагрузки, доработаем middleware.py. Добавим возможность определить путь к пользовательской функции в файле настроек Django.

from django.conf import settings
from django.core.exceptions import PermissionDenied
from django.urls import resolve
from django.utils.module_loading import import_string
from netaddr import IPAddress, IPSet

DEFAULT_GETTER = 'core.middleware.get_remote_addr'


def get_remote_addr(request):
    return request.META['REMOTE_ADDR']


def get_ipaddr(request):
    path = getattr(settings, 'ADMIN_IP_GETTER', DEFAULT_GETTER)
    func = import_string(path)
    return IPAddress(func(request))


def get_ipset_from_settings(name):
    return IPSet(getattr(settings, name, []))


class AdminWhitelistMiddleware:
    """Limits login to specific IP's in Django 3"""

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        current_url = resolve(request.path_info)
        is_admin_app = (current_url.app_name == 'admin')
        whitelist = get_ipset_from_settings('ADMIN_WHITELIST')
        if is_admin_app and not get_ipaddr(request) in whitelist:
            raise PermissionDenied
        return self.get_response(request)

Теперь можем указать в настройке ADMIN_IP_GETTER путь к пользовательской функции для извлечения IP-адреса. Например, метод get_ip() из пакета ipware учитывает заголовок X-Forwarded-For:

ADMIN_IP_GETTER = 'ipware.ip.get_ip'