Другое

Django Rest Framework: api_view против csrf_exempt – разъяснение

Различия между декораторами @api_view и @csrf_exempt в Django Rest Framework. Узнайте, когда использовать каждый, их влияние на безопасность и практики.

В чём разница между декораторами @api_view и @csrf_exempt в Django Rest Framework? Какой из них более подходящий для проекта, и в каких конкретных случаях их следует использовать?

The @api_view и @csrf_exempt декораторы в Django Rest Framework выполняют фундаментально разные задачи. @api_view превращает функции‑обработчики в совместимые с DRF представления с автоматическим исключением CSRF для определённых HTTP‑методов, тогда как @csrf_exempt явно отключает защиту от CSRF для любого представления. Для большинства проектов REST‑API предпочтительнее @api_view, поскольку он обеспечивает полный набор функционала DRF, а @csrf_exempt следует использовать только в тех случаях, когда необходимо явно отключить CSRF за пределами того, что делает DRF автоматически.

Содержание

Понимание декоратора @api_view

Декоратор @api_view является ядром Django Rest Framework и предназначен специально для создания API‑конечных точек. Согласно официальной документации DRF, он «принимает список HTTP‑методов, на которые ваше представление должно реагировать» и преобразует функции‑обработчики в подклассы APIView.

Ключевые особенности @api_view:

  • Автоматическое управление CSRF: Декоратор автоматически исключает CSRF‑защиту для определённых HTTP‑методов. Как отмечено в блоге Excellence Technologies, «традиционный POST‑запрос в Django требует CSRF‑токен. Но @api_view удаляет это тоже».
  • Указание методов: Требуется явное объявление разрешённых HTTP‑методов. Как указано в руководстве TestDriven.io, «он принимает список разрешённых методов для представления в качестве аргумента».
  • Встроенная функциональность: Предоставляет классы Response и Request, автоматические ответы 405 Method Not Allowed и обработку исключений ParseError.
  • Поддержка функций‑обработчиков: Как отмечено в статье GeeksforGeeks, «@api_view – это декоратор из модуля rest_framework.decorators, и он является базовым классом для всех представлений Django REST framework».

Понимание декоратора @csrf_exempt

Декоратор @csrf_exempt – стандартный декоратор Django, который явно отключает защиту от Cross‑Site Request Forgery для представления. Согласно документации Django, он «отмечает представление и исключает его из защиты, которую обеспечивает middleware для всех представлений».

Ключевые особенности @csrf_exempt:

  • Эксперимент по безопасности: Как объясняется в ответе на Stack Overflow What is @csrf_exempt in Django?, «если вы добавите @csrf_exempt в начало вашего представления, вы фактически говорите, что токен не нужен. Это исключение безопасности, которое нужно принимать всерьёз».
  • Общий признак: Работает с любыми представлениями Django, а не только с представлениями DRF.
  • Обработка классов‑обработчиков: Для классов‑обработчиков необходимо применить декоратор к целому классу, а не к отдельным методам. Как показано в обсуждении Google Groups, «он принимается только если я оборачиваю весь класс в декоратор».
  • Ручной контроль CSRF: Предоставляет явный контроль над защитой от CSRF, когда это необходимо.

Ключевые различия между декораторами

Функция @api_view @csrf_exempt
Назначение Преобразует функции‑обработчики в представления DRF Отключает защиту от CSRF
Область применения Специфично для DRF Общий декоратор Django
Обработка CSRF Автоматическое исключение для определённых методов Явное исключение
Тип представления Только функции‑обработчики Любое представление Django
Необходимость Для функций‑обработчиков DRF Необязательно, но при необходимости
Функциональность Предоставляет возможности DRF Только отключает CSRF

Основное различие состоит в том, что @api_view предназначен для включения функционала DRF, а @csrf_exempt – для отключения защиты от CSRF. Как отмечено в блоге Stack Hawk, «декоратор csrf_exempt отмечает представление и исключает его из защиты, которую обеспечивает middleware для всех представлений».

Когда использовать @api_view

@api_view более подходит для большинства проектов REST‑API, потому что:

  1. Разработка API: При создании функций‑обработчиков API, которым нужны возможности DRF, такие как классы Request/Response, коды статуса и автоматическая согласованность контента.
  2. Стандартизированные ответы API: При желании получить единообразные ответы API с корректными HTTP‑кодами и форматами.
  3. Контроль методов: При необходимости явно управлять, какие HTTP‑методы поддерживает представление.
  4. Автоматическое управление CSRF: При желании автоматически исключать CSRF для методов POST, PUT, DELETE без ручной настройки.

Как отмечено в обсуждении Stack Overflow, «после чтения документации по представлениям, APIView наследует django class‑based View. Поэтому вы будете использовать декоратор api_view для представлений, которые потребляют ваш API».

Когда использовать @csrf_exempt

@csrf_exempt следует использовать в специфических сценариях:

  1. API без сессий: При создании API, которые не используют аутентификацию сессиями и должны принимать запросы от внешних клиентов.
  2. Интеграция с внешними сервисами: При интеграции с внешними сервисами, которые не могут предоставить CSRF‑токен.
  3. Наследуемые системы: При работе с устаревшими системами, которые не могут обрабатывать требования CSRF.
  4. Явный контроль безопасности: При необходимости сознательно отключить защиту от CSRF для конкретных представлений.

Как упомянуто в обсуждении Google Groups, «представления DRF по умолчанию исключены из CSRF, если только вы не используете UserLoggedInAuthentication, которая явно требует его».

Лучшие практики и рекомендации

Для большинства современных проектов REST‑API @api_view обычно предпочтительнее, потому что:

  • Полный набор функционала: Предоставляет все возможности DRF, включая CSRF‑обработку.
  • Лучше безопасность: Автоматическое исключение CSRF на основе HTTP‑методов более безопасно, чем blanket‑exemption.
  • Стандартизация: Обеспечивает единообразное поведение API по всему приложению.
  • Будущее: Является частью экосистемы DRF с постоянной поддержкой и развитием.

Однако @csrf_exempt имеет своё место, когда:

  • Вы работаете с представлениями, не являющимися DRF, и им требуется исключение CSRF.
  • Вам нужен явный контроль над защитой от CSRF за пределами того, что делает DRF по умолчанию.
  • Вы создаёте API для конкретных случаев, требующих ручного управления CSRF.

Согласно документации Django, защита от CSRF – важная мера безопасности, поэтому любое исключение должно быть тщательно обосновано и правильно задокументировано.

Примеры кода

Пример @api_view

python
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status

@api_view(['GET', 'POST'])
def snippet_list(request):
    """
    Список всех фрагментов кода или создание нового фрагмента
    """
    if request.method == 'GET':
        # Обработка GET‑запроса
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return Response(serializer.data)
    
    elif request.method == 'POST':
        # Обработка POST‑запроса (автоматически CSRF‑исключено)
        serializer = SnippetSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Пример @csrf_exempt

python
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
import json

@csrf_exempt
def webhook_receiver(request):
    """
    Внешняя точка входа webhook, не использующая аутентификацию сессией
    """
    if request.method == 'POST':
        # Обработка внешнего webhook (явно CSRF‑исключено)
        data = json.loads(request.body)
        process_webhook_data(data)
        return JsonResponse({'status': 'success'})

Совместное использование

python
from rest_framework.decorators import api_view
from django.views.decorators.csrf import csrf_exempt

@api_view(['POST'])
@csrf_exempt
def legacy_api_endpoint(request):
    """
    Устаревший API‑эндпоинт с возможностями DRF и явным исключением CSRF
    """
    # Код представления здесь
    pass

В итоге, @api_view является предпочтительным выбором для большинства разработки REST‑API в Django Rest Framework, поскольку он обеспечивает полный набор функционала DRF и корректно обрабатывает CSRF. @csrf_exempt следует использовать только при необходимости явно отключить CSRF для не‑DRF представлений или в особых случаях, где требуется ручное управление безопасностью.

Источники

  1. Django REST framework – Документация по представлениям
  2. Документация Django – Защита от CSRF
  3. TestDriven.io – Руководство по представлениям DRF
  4. GeeksforGeeks – Функциональные представления в DRF
  5. Stack Overflow – Django rest framework api_view vs normal view
  6. Stack Overflow – Что такое @csrf_exempt в Django?
  7. Stack Hawk – Руководство по защите от CSRF в Django
  8. Excellence Technologies – Django Rest API View
  9. Google Groups – csrf_exempt decorator and class based views
  10. Google Groups – Disabling CSRF protection in DRF

Заключение

Ключевые различия между @api_view и @csrf_exempt очевидны и специфичны по назначению:

  • @api_view предназначен для превращения функций‑обработчиков в представления DRF с автоматическим исключением CSRF для определённых методов.
  • @csrf_exempt – общий декоратор Django, который явно отключает защиту от CSRF для любого представления.

Для большинства проектов REST‑API @api_view более подходит, поскольку он обеспечивает полный набор возможностей DRF и корректно обрабатывает CSRF. @csrf_exempt следует использовать только при необходимости явно отключить CSRF для не‑DRF представлений или при особых требованиях безопасности.

Авторы
Проверено модерацией
Модерация