JavaRush /Курсы /Модуль 3: Django /Практическое занятие по настройке безопасности в Django R...

Практическое занятие по настройке безопасности в Django REST Framework

Модуль 3: Django
21 уровень , 8 лекция
Открыта

Сегодня мы будем практиковаться, а именно — настраивать безопасность API, используя сразу несколько изученных инструментов.

Постановка задачи

В рамках нашего учебного приложения нам нужно:

  1. Защитить эндпоинты API таким образом, чтобы доступ к ним был ограничен в зависимости от роли пользователя.
    • Аутентифицированные пользователи с ролью "пользователь" смогут читать свои данные.
    • Администраторы смогут выполнять любые операции.
    • Анонимные пользователи смогут обращаться только к публичным данным.
  1. Настроить CORS, чтобы API мог взаимодействовать с внешним фронтендом.

  2. Включить HTTPS для обеспечения безопасного обмена данными.

  3. Добавить мониторинг событий безопасности с помощью Django Signals:

    • Логировать успешные авторизации.
    • Реагировать на подозрительные действия, такие как попытки входа с неправильными паролями.

Реализация ролевой модели

Начнем с настройки доступа на основе ролей. В нашем приложении уже должна быть модель пользователей, но сейчас мы добавим поле для хранения роли пользователя.

Шаг 1: дополнение модели пользователя

from django.contrib.auth.models import AbstractUser
from django.db import models

class CustomUser(AbstractUser):
    ROLE_CHOICES = (
        ('user', 'User'),
        ('admin', 'Admin'),
    )
    role = models.CharField(max_length=10, choices=ROLE_CHOICES, default='user')

    def is_admin(self):
        return self.role == 'admin'

    def is_user(self):
        return self.role == 'user'
Пояснение:

мы добавили поле role с выбором ролей. Теперь у нас есть пользователи с ролями "user" и "admin".

Шаг 2: создание кастомного разрешения

Теперь создадим разрешение, которое позволяет доступ только пользователям с определенной ролью.

from rest_framework.permissions import BasePermission

class IsAdminUserOrReadOnly(BasePermission):
    """
    Разрешение для администраторов или только для чтения.
    """
    def has_permission(self, request, view):
        # Проверяем метод запроса. Если это безопасный (GET/HEAD/OPTIONS), доступ открыт.
        if request.method in ['GET', 'HEAD', 'OPTIONS']:
            return True

        # Если метод небезопасный, проверяем, что пользователь администратор.
        return request.user.is_authenticated and request.user.role == 'admin'

Шаг 3: применение разрешения к представлениям

Теперь добавим разрешение к эндпоинтам в нашем API.

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated

from .permissions import IsAdminUserOrReadOnly

class UserDataView(APIView):
    """
    Эндпоинт для получения данных пользователя.
    """
    permission_classes = [IsAuthenticated]

    def get(self, request):
        return Response({"message": "Привет, пользователь!"})

class AdminDataView(APIView):
    """
    Административный эндпоинт.
    """
    permission_classes = [IsAdminUserOrReadOnly]

    def post(self, request):
        return Response({"message": "Привет, админ!"})

Настройка CORS

Прежде чем фронтенд сможет обращаться к нашему API, нужно настроить CORS. Для этого воспользуемся библиотекой django-cors-headers.

Шаг 1: установка библиотеки

Установите пакет с помощью pip:

pip install django-cors-headers

Шаг 2: настройка CORS

Добавьте библиотеку в настройки Django:

INSTALLED_APPS += ['corsheaders']

MIDDLEWARE.insert(0, 'corsheaders.middleware.CorsMiddleware')

CORS_ALLOWED_ORIGINS = [
    "http://localhost:3000",  # Домены, которым разрешен доступ
    "https://example.com",
]

CORS_ALLOW_METHODS = [
    "GET",
    "POST",
    "PUT",
    "DELETE",
    "OPTIONS",
]
Примечание:

Не забудьте указать допустимые источники (домен или localhost) в CORS_ALLOWED_ORIGINS.

Включение HTTPS

Для локальной разработки можно использовать самоподписанный сертификат. В продакшене рекомендуется использовать Let's Encrypt или другой надежный сервис.

Шаг 1: генерация сертификатов для разработки

Сгенерируйте самоподписанный сертификат:

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes

Добавьте SSL-сертификат в настройки проекта. В settings.py:

SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

# Для разработки
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

Запускайте сервер с указанием сертификатов:

python manage.py runserver_plus --cert-file cert.pem

Для использования HTTPS в продакшене ознакомьтесь с документацией Django.

Мониторинг событий через Django Signals

Мы будем логировать успешные авторизации и отправлять уведомления об ошибочных попытках входа.

Шаг 1: настройка сигналов

Создайте файл signals.py в вашем приложении.

from django.contrib.auth.signals import user_logged_in, user_login_failed
from django.dispatch import receiver
import logging

logger = logging.getLogger(__name__)

@receiver(user_logged_in)
def log_successful_login(sender, request, user, **kwargs):
    logger.info(f"Успешный вход: {user.username} с IP {get_client_ip(request)}")

@receiver(user_login_failed)
def log_failed_login(sender, credentials, request, **kwargs):
    logger.warning(f"Неудачная попытка входа для {credentials.get('username')} с IP {get_client_ip(request)}")

def get_client_ip(request):
    """Получение IP-адреса клиента."""
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        return x_forwarded_for.split(',')[0]
    return request.META.get('REMOTE_ADDR')

Шаг 2: подключение сигналов

В файле apps.py подключите файл сигналов.

class MyAppConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'myapp'

    def ready(self):
        import myapp.signals

Тестирование безопасности

Теперь, когда все настроено, выполните интеграционные тесты:

  • Убедитесь, что эндпоинты API корректно ограничивают доступ.
  • Проверьте возможности CORS с фронтендом.
  • Протестируйте HTTPS с сертификатами.
  • Проверьте, что события авторизации логируются.

Пример теста с использованием pytest

import pytest
from rest_framework.test import APIClient

@pytest.mark.django_db
def test_admin_access():
    client = APIClient()
    response = client.post('/admin-endpoint/')
    assert response.status_code == 403  # Только для админов

На этом практическое занятие завершено. Мы настроили основные аспекты безопасности: ограничения по ролям, CORS, HTTPS и мониторинг событий. Эти методы обеспечат высокий уровень защиты API в реальном приложении.

1
Задача
Модуль 3: Django, 21 уровень, 8 лекция
Недоступна
Создание кастомного разрешения
Создание кастомного разрешения
1
Задача
Модуль 3: Django, 21 уровень, 8 лекция
Недоступна
Включение HTTPS и проверка безопасности
Включение HTTPS и проверка безопасности
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ