Взгляд на разборку может прояснить, что происходит:
>>> def f():
... print a
... print b
... a = 1
>>> import dis
>>> dis.dis(f)
2 0 LOAD_FAST 0 (a)
3 PRINT_ITEM
4 PRINT_NEWLINE
3 5 LOAD_GLOBAL 0 (b)
8 PRINT_ITEM
9 PRINT_NEWLINE
4 10 LOAD_CONST 1 (1)
13 STORE_FAST 0 (a)
16 LOAD_CONST 0 (None)
19 RETURN_VALUE
Как вы можете видеть, байт-код для доступа к a есть LOAD_FAST
, а для b, LOAD_GLOBAL
. Это связано с тем, что компилятор идентифицировал, что a назначается внутри функции, и классифицирует его как локальную переменную. Механизм доступа для местных жителей принципиально отличается для глобальных переменных - им статически присваивается смещение в таблице переменных фрейма, что означает, что поиск является быстрым индексом, а не более дорогим исканием dict, как для глобальных. Из-за этого Python считывает строку print a
как «получает значение локальной переменной« a », содержащееся в слоте 0, и печатает его», и когда он обнаруживает, что эта переменная все еще не инициализирована, возникает исключение.
Почему эта ошибка происходит?
Это происходит из-за схемы 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})
Если вы не хотите использовать аутентификацию на основе сеанса, вы можете удалить Session Authentication
из REST_AUTHENTICATION_CLASSES и автоматически удалить все проблемы на основе csrf. Но в этом случае Apache с возможностью просмотра может не работать.
Кроме того, эта ошибка не должна совпадать даже с аутентификацией сеанса. Вы должны использовать настраиваемую аутентификацию, такую как TokenAuthentication для своего apis, и не забудьте отправить Accept:application/json
и Content-Type:application/json
(при условии, что вы используете json) в своих запросах вместе с токеном аутентификации.
Мое решение показано ударом. Просто украсьте мой класс.
from django.views.decorators.csrf import csrf_exempt
@method_decorator(csrf_exempt, name='dispatch')
@method_decorator(basic_auth_required(
target_test=lambda request: not request.user.is_authenticated
), name='dispatch')
class GenPedigreeView(View):
pass
Если вы используете эксклюзивную виртуальную среду для своего приложения, вы можете использовать следующий подход без каких-либо других приложений.
То, что вы наблюдали, происходит, потому что rest_framework/authentication.py
имеет этот код в authenticate
метод класса SessionAuthentication
:
self.enforce_csrf(request)
Вы можете изменить класс Request
, чтобы иметь свойство, называемое csrf_exempt
, и инициализировать его внутри вашего соответствующего класса вида True
, если вы не хотите Проверка CSRF. Например:
Затем измените приведенный выше код следующим образом:
if not request.csrf_exempt:
self.enforce_csrf(request)
В классе Request
есть некоторые связанные изменения. Полная реализация доступна здесь (с полным описанием): https://github.com/piaxis/django-rest-framework/commit/1bdb872bac5345202e2f58728d0e7fad70dfd7ed
Изменить urls.py
Если вы управляете своими маршрутами в urls.py, вы можете связать свои маршруты с помощью csrf_exempt (), чтобы исключить их из промежуточного программного обеспечения проверки CSRF.
from django.conf.urls import patterns, url
from django.views.decorators.csrf import csrf_exempt
import views
urlpatterns = patterns('',
url(r'^object/$', csrf_exempt(views.ObjectView.as_view())),
...
)
Альтернативно, в качестве декоратора Некоторые могут найти использование декоратора @csrf_exempt, более подходящего для их нужд
, например,
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
@csrf_exempt
def my_view(request):
return HttpResponse('Hello world')
должен получить Job Done!
Для всех, кто не нашел полезного ответа. Да DRF автоматически удаляет CSRF-защиту, если вы не используете SessionAuthentication
AUTHENTICATION CLASS, например, многие разработчики используют только JWT:
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
Но проблема CSRF not set
может быть вызвана по другой причине, поскольку fm]
вместо
url(r'^api/signup/', CreateUserView.as_view()),
У меня такая же проблема. Я следил за этой ссылкой , и это сработало. Решение состоит в том, чтобы создать промежуточное программное обеспечение
Добавить файл 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,
)