Как сделать POST простой JSON с помощью Django REST Framework? Недопустимый токен CSRF или неверный
Поражаю, кто-то покажет мне, как сделать простой запрос POST, используя JSON с картой Django REST. Я не вижу никаких примеров этого в учебнике в любом месте?
Вот мой объект модели роли, который я хотел бы ПОСТ. Это будет совершенно новая роль, которую я бы хотел добавить в базу данных, но я получаю ошибку 500.
{
"name": "Manager",
"description": "someone who manages"
}
Вот мой запрос на завивание в командной строке bash:
curl -X POST -H "Content-Type: application/json" -d '[
{
"name": "Manager",
"description": "someone who manages"
}]'
http://localhost:8000/lakesShoreProperties/role
URL
http://localhost:8000/lakesShoreProperties/roles
Работает с запросом GET, и я могу вытащить все роли в базе данных, но я не могу создать никаких новых ролей. У меня нет разрешений. Я использую стандартный вид в views.py
class RoleDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Role.objects.all()
serializer_class = RoleSerializer
format = None
class RoleList(generics.ListCreateAPIView):
queryset = Role.objects.all()
serializer_class = RoleSerializer
format = None
И в моем urls.py
для этого приложения соответствующие сопоставления URL-адресов верны:
url(r'^roles/$', views.RoleList.as_view()),
url(r'^role/(?P<pk>[0-9]+)/$', views.RoleDetail.as_view()),
Сообщение об ошибке:
{
"detail": "CSRF Failed: CSRF token missing or incorrect."
}
Что здесь происходит и что для этого нужно? Является ли localhost кросс-сайтом? Я добавил @csrf_exempt
в RoleDetail
и RoleList
, но он ничего не меняет. Может ли этот декоратор быть добавлен в класс или его нужно добавить к методу?
Добавляя украшение @csrf_exempt
, моя ошибка становится:
Request Method: POST
Request URL: http://127.0.0.1:8000/lakeshoreProperties/roles/
Django Version: 1.5.1
Exception Type: AttributeError
Exception Value:
'function' object has no attribute 'as_view'
Затем я отключил CSRF через все приложение, и теперь я получаю это сообщение:
{ "non_field_errors": [ "Недопустимые данные" ]}, когда мой JSON-объект, который я знаю, действителен json. Это ошибка, отличная от поля, но я застрял здесь.
Ну, получается, что мой json недействителен?
{
"name": "admin",
"description": "someone who administrates"
}
против
[
{
"name": "admin",
"description": "someone who administrates"
}
]
Наличие прилагаемых скобок [] приводит к сбою запроса POST. Но используя валидатор jsonlint.com, оба моих объекта json проверяются.
Обновление: проблема заключалась в отправке POST с PostMan, а не в бэкэнд. См. qaru.site/info/130454/...
Ответы
Ответ 1
Вероятно, вам нужно отправить маркер CSRF с вашим запросом. Проверьте https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/#csrf-ajax
Обновление. Поскольку вы уже пытались исключить CSRF, возможно, это может помочь (в зависимости от используемой версии Django): fooobar.com/questions/130457/... p >
Ответ 2
CSRF освобождается по умолчанию в Django REST Framework. Поэтому запрос curl POST работает нормально. Запрос запроса POSTMAN возвратил CSRF неправильно, потому что POSTMAN включил токен csrf, если он найден в Cookies. Вы можете решить эту проблему, очистив Cookies.
Ответ 3
Это из настроек REST Framework. в вашем settings.py
файле, ваш REST_FRAMEWORK
должен иметь следующее.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
),
}
Это приведет к тому, что REST Framework будет использовать аутентификацию на токенах вместо аутентификации csrf. И, установив разрешение на AllowAny
, вы можете аутентифицироваться только там, где хотите.
Ответ 4
Хорошо, теперь, конечно, я возвращаю то, что я сказал. CSRF работает по назначению.
Я делал запрос POST, используя chrome-плагин под названием POSTMAN.
Мой запрос POST не работает с включенным CSRF.
Но запрос POST для завивки с использованием
curl -X POST -H "Content-Type: application/json" -d '
{
"name": "Manager",
"description": "someone who manages"
}' http://127.0.0.1:8000/lakeshoreProperties/roles/
отлично работает...
Мне пришлось снять фигурные скобки, т.е. [], И убедиться, что в ролях есть слэш после "s", т.е. Роли /, а csrf enabled не вызывает никаких ошибок.
Я не уверен, какая разница между вызовами с использованием POSTMAN - с помощью curl, но POSTMAN запускается в веб-браузере, что является самой большой разницей. Тем не менее, я отключил csrf для всего класса RoleList, но один идентичный запрос работает с Curl, но с POSTMAN не работает.
Ответ 5
Чтобы обновить текущий статус и подытожить несколько ответов:
Запросы AJAX, выполненные в том же контексте, что и API, с которыми они взаимодействуют, обычно используют SessionAuthentication
. Это гарантирует, что, как только пользователь войдет в систему, любые сделанные AJAX-запросы могут быть аутентифицированы с использованием той же аутентификации на основе сеанса, которая используется для остальной части веб-сайта.
Запросы AJAX, выполненные на другом сайте из API, с которыми они общаются, обычно должны использовать схему проверки подлинности, отличную от сеанса, такую как TokenAuthentication
.
Поэтому ответы, рекомендующие заменить SessionAuthentication
на TokenAuthentication
, могут решить проблему, но не обязательно полностью верны.
Чтобы защититься от этих типов атак, вам нужно сделать две вещи:
-
Убедитесь, что "безопасные" HTTP-операции, такие как GET
, HEAD
и OPTIONS
, не могут использоваться для изменения любого состояния на стороне сервера.
-
Убедитесь, что любые "небезопасные" HTTP-операции, такие как POST
, PUT
, PATCH
и DELETE
, всегда требуют действительного токена CSRF. Если вы используете SessionAuthentication
, вам нужно включить допустимые токены CSRF для любых операций POST
, PUT
, PATCH
или DELETE
.
Чтобы сделать запросы AJAX, вам нужно включить токен CSRF в HTTP-заголовок, как описано в документации Django.
Поэтому важно, чтобы csrf был включен в заголовок, например этот ответ.
Ссылка: Работа с документацией AJAX, CSRF и CORS, Django REST.
Ответ 6
Как вы сказали, ваш URL был
http://localhost:8000/lakesShoreProperties/roles
У почтальона есть некоторые проблемы с localhost.
Отправка POST на 127.0.0.1:8000/your-api/endpoint
вместо этого сделала трюк для меня.
Ответ 7
Вы также можете отключить CSRF для создания своего собственного промежуточного программного обеспечения:
class DisableCSRF(object):
def process_request(self, request):
setattr(request, '_dont_enforce_csrf_checks', True)
И включите это промежуточное программное обеспечение в файл settings.py в MIDDLEWARE_CLASSES.
Ответ 8
у старого Postman возникает проблема с токенами csrf, поскольку он не работает с кукисами.
Я предлагаю вам перейти на новую версию postman, она работает с файлами cookie, и вы снова не столкнетесь с этой проблемой.
Ответ 9
если вы установили разрешение AllowAny
и столкнулись с проблемой csrf
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny'
]
}
тогда размещение следующего в settings.py
решит проблему
REST_SESSION_LOGIN = False