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
- Понимание декоратора @csrf_exempt
- Ключевые различия между декораторами
- Когда использовать @api_view
- Когда использовать @csrf_exempt
- Лучшие практики и рекомендации
- Примеры кода
Понимание декоратора @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, потому что:
- Разработка API: При создании функций‑обработчиков API, которым нужны возможности DRF, такие как классы Request/Response, коды статуса и автоматическая согласованность контента.
- Стандартизированные ответы API: При желании получить единообразные ответы API с корректными HTTP‑кодами и форматами.
- Контроль методов: При необходимости явно управлять, какие HTTP‑методы поддерживает представление.
- Автоматическое управление CSRF: При желании автоматически исключать CSRF для методов POST, PUT, DELETE без ручной настройки.
Как отмечено в обсуждении Stack Overflow, «после чтения документации по представлениям, APIView наследует django class‑based View. Поэтому вы будете использовать декоратор api_view для представлений, которые потребляют ваш API».
Когда использовать @csrf_exempt
@csrf_exempt следует использовать в специфических сценариях:
- API без сессий: При создании API, которые не используют аутентификацию сессиями и должны принимать запросы от внешних клиентов.
- Интеграция с внешними сервисами: При интеграции с внешними сервисами, которые не могут предоставить CSRF‑токен.
- Наследуемые системы: При работе с устаревшими системами, которые не могут обрабатывать требования CSRF.
- Явный контроль безопасности: При необходимости сознательно отключить защиту от 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
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
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'})
Совместное использование
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 представлений или в особых случаях, где требуется ручное управление безопасностью.
Источники
- Django REST framework – Документация по представлениям
- Документация Django – Защита от CSRF
- TestDriven.io – Руководство по представлениям DRF
- GeeksforGeeks – Функциональные представления в DRF
- Stack Overflow – Django rest framework api_view vs normal view
- Stack Overflow – Что такое @csrf_exempt в Django?
- Stack Hawk – Руководство по защите от CSRF в Django
- Excellence Technologies – Django Rest API View
- Google Groups – csrf_exempt decorator and class based views
- 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 представлений или при особых требованиях безопасности.