Я знаю, что есть ответы на 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 только для этого приложения?
Почему эта ошибка происходит?
Это происходит из-за стандартной схемы 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.
Простое решение:
В 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})
Если вы не хотите использовать аутентификацию на основе сеанса, вы можете удалить "Аутентификацию сеанса" из REST_AUTHENTICATION_CLASSES и автоматически удалить все проблемы на основе csrf. Но в этом случае Apache с возможностью просмотра может не работать. Кроме того, эта ошибка не должна появляться даже при проверке сеанса. Вы должны использовать пользовательскую аутентификацию, такую как TokenAuthentication для своей apis, и не забудьте отправить Accept:application/json
и Content-Type:application/json
(если вы используете json) в своих запросах вместе с токеном аутентификации.
Меня поражает та же проблема. Я выполнил эту ссылку, и она сработала. Решение заключается в создании промежуточного программного обеспечения
Добавьте файл 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,
)
Для всех, кто какой-то ответ не поможет. Да 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()),
Если вы используете эксклюзивную виртуальную среду для своего приложения, вы можете использовать следующий подход без каких-либо других приложений.
То, что вы наблюдаете, происходит потому, что 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