如何使用 Django REST Framework 制作一个 POST 简单的 JSON?CSRF 令牌丢失或不正确
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17507206/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to make a POST simple JSON using Django REST Framework? CSRF token missing or incorrect
提问by user798719
Would appreciate someone showing me how to make a simple POST request using JSON with Django REST framework. I do not see any examples of this in the tutorial anywhere?
很感激有人向我展示如何使用 JSON 和 Django REST 框架发出简单的 POST 请求。我在教程中的任何地方都没有看到任何示例?
Here is my Role model object that I'd like to POST. This will be a brand new Role that I'd like to add to the database but I'm getting a 500 error.
这是我想发布的角色模型对象。这将是一个全新的角色,我想添加到数据库中,但出现 500 错误。
{
"name": "Manager",
"description": "someone who manages"
}
Here is my curl request at a bash terminal prompt:
这是我在 bash 终端提示符下的 curl 请求:
curl -X POST -H "Content-Type: application/json" -d '[
{
"name": "Manager",
"description": "someone who manages"
}]'
http://localhost:8000/lakesShoreProperties/role
The URL
网址
http://localhost:8000/lakesShoreProperties/roles
DOES work with a GET request, and I can pull down all the roles in the database, but I can not seem to create any new Roles. I have no permissions set. I'm using a standard view in views.py
确实适用于 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
And in my urls.pyfor this app, the relevant url - view mappings are correct:
在我urls.py的这个应用程序中,相关的 url - 视图映射是正确的:
url(r'^roles/$', views.RoleList.as_view()),
url(r'^role/(?P<pk>[0-9]+)/$', views.RoleDetail.as_view()),
Error message is:
错误信息是:
{
"detail": "CSRF Failed: CSRF token missing or incorrect."
}
What is going on here and what is the fix for this? Is localhost a cross site request? I have added @csrf_exemptto RoleDetailand RoleListbut it doesn't seem to change anything. Can this decorator even be added to a class, or does it have to be added to a method?
Adding the @csrf_exemptdecorate, my error becomes:
这里发生了什么,对此有什么解决方法?localhost 是跨站点请求吗?我已经添加@csrf_exempt到RoleDetailandRoleList但它似乎没有改变任何东西。这个装饰器甚至可以添加到类中,还是必须添加到方法中?添加@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'
Then I disabled CSRF throughtout the entire app, and I now get this message:
然后我在整个应用程序中禁用了 CSRF,现在我收到了这条消息:
{"non_field_errors": ["Invalid data"]} when my JSON object I know is valid json. It's a non-field error, but I'm stuck right here.
{"non_field_errors": ["Invalid data"]} 当我知道我的 JSON 对象是有效的 json 时。这是一个非现场错误,但我被困在这里。
Well, it turns out that my json was not valid?
好吧,原来我的json无效?
{
"name": "admin",
"description": "someone who administrates"
}
vs
对比
[
{
"name": "admin",
"description": "someone who administrates"
}
]
Having the enclosing brackets [], causes the POST request to fail. But using the jsonlint.com validator, both of my json objects validate.
有括号 [],会导致 POST 请求失败。但是使用 jsonlint.com 验证器,我的两个 json 对象都会验证。
Update: The issue was with sending the POST with PostMan, not in the backend. See https://stackoverflow.com/a/17508420/203312
更新:问题在于使用 PostMan 发送 POST,而不是在后端。见https://stackoverflow.com/a/17508420/203312
采纳答案by stellarchariot
You probably need to send along the CSRF token with your request. Check out https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/#csrf-ajax
您可能需要随请求一起发送 CSRF 令牌。查看https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/#csrf-ajax
Update: Because you've already tried exempting CSRF, maybe this could help (depending on which version of Django you're using): https://stackoverflow.com/a/14379073/977931
更新:因为您已经尝试免除 CSRF,所以这可能会有所帮助(取决于您使用的 Django 版本):https: //stackoverflow.com/a/14379073/977931
回答by Terry Lam
CSRF is exempted by default in Django REST Framework. Therefore, curl POST request works fine. POSTMAN request call returned CSRF incorrect because POSTMAN included csrf token if it is found in Cookies. You can solve this by cleaning up Cookies.
CSRF 在 Django REST Framework 中默认是免除的。因此,curl POST 请求工作正常。POSTMAN 请求调用返回的 CSRF 不正确,因为 POSTMAN 包含 csrf 令牌(如果它在 Cookies 中找到)。您可以通过清理 Cookie 来解决此问题。
回答by pharingee
It's from your REST Framework settings. in your settings.pyfile, your REST_FRAMEWORKshould have the following.
它来自您的 REST 框架设置。在您的settings.py文件中,您REST_FRAMEWORK应该具有以下内容。
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
),
}
This will set your REST Framework to use token authentication instead of csrf authentication. And by setting the permission to AllowAny, you can authenticate only where you want to.
这会将您的 REST 框架设置为使用令牌身份验证而不是 csrf 身份验证。并且通过将权限设置为AllowAny,您可以仅在您想要的地方进行身份验证。
回答by user798719
OK, well now of course I take back what I said. CSRF does work as intended.
好吧,现在我当然收回我说的话。CSRF 确实按预期工作。
I was making a POST request using a chrome plugin called POSTMAN. My POST request fails with CSRF enabled.
我正在使用名为 POSTMAN 的 chrome 插件发出 POST 请求。我的 POST 请求在启用 CSRF 的情况下失败。
But a curl POST request using
但是使用 curl POST 请求
curl -X POST -H "Content-Type: application/json" -d '
{
"name": "Manager",
"description": "someone who manages"
}' http://127.0.0.1:8000/lakeshoreProperties/roles/
works fine... I had to take off the braces, i.e., [], and make sure there is a slash after the 's' in roles, i.e., roles/, and csrf enabled did not throw any errors.
工作正常...我不得不取下大括号,即 [],并确保角色中的“s”后有一个斜杠,即角色/,并且启用 csrf 没有抛出任何错误。
I'm not sure what the difference between calling using POSTMAN is vs using curl, but POSTMAN is run in the web browser which is the biggest difference. That said, I disabled csrf for the entire class RoleList but one identical request works with Curl, but fails with POSTMAN.
我不确定使用 POSTMAN 调用与使用 curl 之间的区别是什么,但 POSTMAN 在 Web 浏览器中运行,这是最大的区别。也就是说,我为整个类 RoleList 禁用了 csrf,但是一个相同的请求适用于 Curl,但使用 POSTMAN 失败。
回答by Wtower
To give an update on current status, and sum up a few answers:
提供有关当前状态的更新,并总结一些答案:
AJAX requests that are made within the same context as the API they are interacting with will typically use
SessionAuthentication. This ensures that once a user has logged in, any AJAX requests made can be authenticated using the same session-based authentication that is used for the rest of the website.AJAX requests that are made on a different site from the API they are communicating with will typically need to use a non-session-based authentication scheme, such as
TokenAuthentication.
在与其交互的 API 相同的上下文中发出的 AJAX 请求通常会使用
SessionAuthentication. 这确保一旦用户登录,任何 AJAX 请求都可以使用与网站其余部分相同的基于会话的身份验证进行身份验证。在与其通信的 API 不同的站点上发出的 AJAX 请求通常需要使用非基于会话的身份验证方案,例如
TokenAuthentication.
Therefore, answers recommending to replace SessionAuthenticationwith TokenAuthenticationmay solve the issue, but are not necessarily totally correct.
因此,建议替换SessionAuthentication为的答案TokenAuthentication可能会解决问题,但不一定完全正确。
To guard against these type of attacks, you need to do two things:
Ensure that the 'safe' HTTP operations, such as
GET,HEADandOPTIONScannot be used to alter any server-side state.Ensure that any 'unsafe' HTTP operations, such as
POST,PUT,PATCHandDELETE, always require a valid CSRF token. If you're usingSessionAuthenticationyou'll need to include valid CSRF tokens for anyPOST,PUT,PATCHorDELETEoperations.In order to make AJAX requests, you need to include CSRF token in the HTTP header, as described in the Django documentation.
要防范此类攻击,您需要做两件事:
确保“安全” HTTP操作,如
GET,HEAD而OPTIONS不能用于改变任何服务器端状态。确保所有“不安全”的HTTP操作,如
POST,PUT,PATCH和DELETE,总是需要一个有效的CSRF令牌。如果你使用SessionAuthentication你需要包括任何有效的CSRF令牌POST,PUT,PATCH或DELETE操作。为了发出 AJAX 请求,您需要在 HTTP 标头中包含 CSRF 令牌,如 Django 文档中所述。
Therefore, it is important that csrf is included in header, as for instance this answersuggests.
因此,将 csrf 包含在标头中很重要,例如this answer建议。
Reference: Working with AJAX, CSRF & CORS, Django REST framework documentation.
回答by Thosse
As you said your URL was
正如你所说,你的网址是
http://localhost:8000/lakesShoreProperties/roles
http://localhost:8000/lakesShoreProperties/roles
Postman has some issues with localhost.
Sending the POST to 127.0.0.1:8000/your-api/endpointinstead did the trick for me.
邮递员对本地主机有一些问题。将 POST 发送到127.0.0.1:8000/your-api/endpoint改为对我有用。
回答by Musharraf Al-tamimi
the old Postmanis having a problem with csrf tokens because it does not working with cookies.
旧邮递员在使用 csrf 令牌时遇到了问题,因为它不适用于 cookie。
I suggest for you to switch to the new version of postman, it works with cookies and you will not face this problem again.
我建议您切换到新版本的postman,它可以与 cookie 一起使用,您将不会再遇到这个问题。
回答by navyad
if you have set AllowAnypermission and you facing with csrf issue
如果您已设置AllowAny权限并且您面临 csrf 问题
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny'
]
}
then placing following in the settings.pywill resolve the issue
然后将以下内容放入settings.py将解决问题
REST_SESSION_LOGIN = False

