Django Rest Framework удалить csrf

Я знаю, что есть ответы на Django Rest Framework, но я не смог найти решение моей проблемы.

У меня есть приложение, имеющее аутентификацию и некоторые функции. Я добавил к нему новое приложение, которое использует Django Rest Framework. Я хочу использовать библиотеку только в этом приложении. Также я хочу сделать запрос POST, и я всегда получаю этот ответ:

{
    "detail": "CSRF Failed: CSRF token missing or incorrect."
}

У меня есть следующий код:

# urls.py
from django.conf.urls import patterns, url


urlpatterns = patterns(
    'api.views',
    url(r'^object/$', views.Object.as_view()),
)

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from django.views.decorators.csrf import csrf_exempt


class Object(APIView):

    @csrf_exempt
    def post(self, request, format=None):
        return Response({'received data': request.data})

Я хочу добавить API, не затрагивая текущее приложение. Итак, мои вопросы: как отключить CSRF только для этого приложения?

Ответ 1

Почему эта ошибка происходит?

Это происходит из-за стандартной схемы SessionAuthentication, используемой DRF. DRF SessionAuthentication использует среду сеансов Django для аутентификации, которая требует проверки CSRF.

Если вы не определяете authentication_classes в своем представлении/просмотре, DRF использует эти классы проверки подлинности как значения по умолчанию.

'DEFAULT_AUTHENTICATION_CLASSES'= (
    'rest_framework.authentication.SessionAuthentication',
    'rest_framework.authentication.BasicAuthentication'
),

Поскольку DRF должен поддерживать как сеансовую, так и несинхронную аутентификацию для одних и тех же представлений, он обеспечивает проверку CSRF только для аутентифицированных пользователей. Это означает, что только аутентифицированные запросы требуют токенов CSRF, а анонимные запросы могут быть отправлены без токенов CSRF.

Если вы используете API стиля AJAX с SessionAuthentication, вам нужно включить действительный токен CSRF для любых "небезопасных" вызовов HTTP-методов, таких как PUT, PATCH, POST or DELETE запросы.

Что делать?

Теперь, чтобы отключить проверку csrf, вы можете создать собственный класс проверки подлинности CsrfExemptSessionAuthentication, который простирается от класса SessionAuthentication по умолчанию. В этом классе аутентификации мы переопределим проверку enforce_csrf(), которая происходила внутри фактического SessionAuthentication.

from rest_framework.authentication import SessionAuthentication, BasicAuthentication 

class CsrfExemptSessionAuthentication(SessionAuthentication):

    def enforce_csrf(self, request):
        return  # To not perform the csrf check previously happening

По вашему мнению, вы можете определить authentication_classes как:

authentication_classes = (CsrfExemptSessionAuthentication, BasicAuthentication)

Это должно обрабатывать ошибку csrf.

Ответ 2

Простое решение:

В views.py используйте скобки CsrfExemptMixin и authentication_classes:

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from django.views.decorators.csrf import csrf_exempt
from braces.views import CsrfExemptMixin


class Object(CsrfExemptMixin, APIView):
    authentication_classes = []

    def post(self, request, format=None):
        return Response({'received data': request.data})

Ответ 3

Если вы не хотите использовать аутентификацию на основе сеанса, вы можете удалить "Аутентификацию сеанса" из REST_AUTHENTICATION_CLASSES и автоматически удалить все проблемы на основе csrf. Но в этом случае Apache с возможностью просмотра может не работать. Кроме того, эта ошибка не должна появляться даже при проверке сеанса. Вы должны использовать пользовательскую аутентификацию, такую ​​как TokenAuthentication для своей apis, и не забудьте отправить Accept:application/json и Content-Type:application/json (если вы используете json) в своих запросах вместе с токеном аутентификации.

Ответ 4

Меня поражает та же проблема. Я выполнил эту ссылку, и она сработала. Решение заключается в создании промежуточного программного обеспечения

Добавьте файл disable.py в одно из ваших приложений (в моем случае это "myapp" )

class DisableCSRF(object):
    def process_request(self, request):
        setattr(request, '_dont_enforce_csrf_checks', True)

И добавьте мини-диск в MIDDLEWARE_CLASSES

MIDDLEWARE_CLASSES = (
myapp.disable.DisableCSRF,
)

Ответ 5

Если вы используете эксклюзивную виртуальную среду для своего приложения, вы можете использовать следующий подход без каких-либо других приложений.

То, что вы наблюдаете, происходит потому, что rest_framework/authentication.py имеет этот код в методе authenticate класса SessionAuthentication:

self.enforce_csrf(request)

Вы можете изменить класс Request, чтобы иметь свойство с именем csrf_exempt и инициализировать его внутри вашего соответствующего класса View до True, если вы не хотите, чтобы CSRF проверили. Например:

Затем измените приведенный выше код следующим образом:

if not request.csrf_exempt:
    self.enforce_csrf(request)

Есть некоторые связанные изменения, которые вы должны сделать в классе Request. Полная реализация доступна здесь (с полным описанием): https://github.com/piaxis/django-rest-framework/commit/1bdb872bac5345202e2f58728d0e7fad70dfd7ed

Ответ 6

Для всех, кто какой-то ответ не поможет. Да DRF автоматически удаляет CSRF-защиту, если вы не используете SessionAuthentication AUTHENTICATION CLASS, например, многие разработчики используют только JWT:

'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ),

Но проблема CSRF not set может возникнуть по какой-то другой причине, поскольку вы не правильно добавили путь к вам:

url(r'^api/signup/', CreateUserView),  # <= error! DRF cant remove CSRF because it is not as_view that does it!

вместо

url(r'^api/signup/', CreateUserView.as_view()),