2015-06-16 7 views
54

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

У меня есть приложение, имеющее аутентификацию и некоторые функции. Я добавил к нему новое приложение, в котором используется 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 только для этого приложения?

+0

вы уже используете @csrf_exempt маркер. Вы можете использовать это на весь вид. Разве это не работает? – mukesh

+0

Нет, у меня все еще есть детали: «CSRF Failed: токен CSRF отсутствует или неверен». сообщение. В заключение я пришел к выводу, что я должен удалить аутентификацию по умолчанию. –

+1

Я столкнулся с ОЧЕНЬ подобной ситуацией, используя аутентификацию Token. Для кого-то еще в той же лодке: http://stackoverflow.com/questions/34789301/django-rest-framework-w-tokenauthentication-issue-with-csrf-cors –

ответ

111

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

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

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

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

С ФПИ должен поддерживать как сессию и проверка подлинности на основе не-сессии для тех же взглядов, что обеспечивает соблюдение проверку 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.

+1

Спасибо, отличный ответ. Там должен быть встроенный способ сделать это в restframework, но в настоящее время это лучшее решение, которое я нашел. – Omer

+1

Спасибо, это сработало! с Django 1.9 – neosergio

+1

Простите, может быть, я пропустил точку, но не является ли угрозой безопасности для обхода/отключения защиты csrf? – Paolo

6

Если вы не хотите использовать аутентификацию на основе сеанса, вы можете удалить Session Authentication из REST_AUTHENTICATION_CLASSES и автоматически устранить все проблемы на основе csrf. Но в этом случае Apache с возможностью просмотра может не работать.

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

3

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

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

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

И добавить middileware к MIDDLEWARE_CLASSES

MIDDLEWARE_CLASSES = (
myapp.disable.DisableCSRF, 
) 
7

Легче решение:

В 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}) 
+1

FYI - http://django-braces.readthedocs.org/en/latest/index.html –

+1

Спасибо, это самое простое решение проблемы. Мой api использует oauth2_provider и токен. –

+0

аххх человек. У меня был CsrfExemptMixin, но у меня не было authentication_classes = []. Спасибо! – MagicLAMP

0

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

То, что вы наблюдали происходит потому, что 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

2

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

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

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

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()), 
Смежные вопросы