CSRF 失败: CSRF 令牌丢失或不正确

我使用的是 Django 1.7和 Django-rest-Framework。

我创建了一个 API,它返回一些 JSON 数据,将其放入我的 settings.py

REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.AllowAny',),
'DEFAULT_RENDERER_CLASSES': (
#   'rest_framework.renderers.XMLRenderer',
'rest_framework.renderers.JSONRenderer',
#   'rest_framework.renderers.BrowsableAPIRenderer',
)
}

当我调用 GET 时,它返回所有的数据,但是当我尝试 PUT/PATCH 时,我得到:

--------Response Headers---------
Status Code: 403
Date: Wed, 29 Oct 2014 18:51:42 GMT
Vary: Cookie
Server: WSGIServer/0.1 Python/2.7.8
Allow: GET, POST, PUT, PATCH, HEAD, OPTIONS
X-Frame-Options: SAMEORIGIN
Content-Type: application/json
---------------------------------


--------Response Body-----------
{"detail": "CSRF Failed: CSRF token missing or incorrect."}
---------------------------------

只有当我登录时才会发生这种情况,如果我是匿名的,我可以正确地使用/PATCH。

我已经尝试与 @csrf_exempt和我得到了错误,我已经包括在设置的 rest_framework.permissions.AllowAny..。

我不知道怎么回事,有人知道问题出在哪吗?

153053 次浏览

When you are using SessionAuthentication, you are using Django's authentication which usually requires CSRF to be checked. Django REST Framework enforces this, only for SessionAuthentication, so you must pass the CSRF token in the X-CSRFToken header.

The Django documentation provides more information on retrieving the CSRF token using jQuery and sending it in requests. The CSRF token is saved as a cookie called csrftoken that you can retrieve from a HTTP response, which varies depending on the language that is being used.

If you cannot retrieve the CSRF cookie, this is usually a sign that you should not be using SessionAuthentication. I recommend looking into TokenAuthentication or OAuth 2.0 depending on your needs.

I had similar problem, I've wrapped my URLs under csrf_exempt method as -

from django.views.decorators.csrf import csrf_exempt


url(r'^api/v1/some-resource$', csrf_exempt(SomeApiView.as_view())),

This is what i did to solve it, i included csrf token to the form and using jquery/ javascrip got the csrf token like this when document loaded

var $crf_token = $('[name="csrfmiddlewaretoken"]').attr('value');

the included it on jquery headers as follow

 $.ajax({
type: "POST",
url: "/api/endpoint/",
data: newEndpoint,
headers:{"X-CSRFToken": $crf_token},
success: function (newEnd) {
console.log(newEnd);
add_end(newEnd);
},
error: function () {
alert("There was an error")
}
});

Get token from cookie:

function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}


var csrftoken = readCookie('csrftoken');

Send token in headers POST request:

  this.$http.post(server,{params: {foo: 'bar'}}, {headers: {"X-CSRFToken":csrftoken }}).then(function (response) {
this.response = response.data;
},
function (response) {
console.log(response);
});

I had a similar problem where I'd wrapped the views with csrf_exempt and was still encountering errors. It turned out that I was getting the URL wrong, so it was resolved to a "not found" callback (which wasn't exempt from CSRF) and was hence throwing an exception before I could be told that the URL was wrong.

1- Search for the Cookie header

enter image description here

2- Separate the csrftoken from the sessionid

3- Add the X-CSRFToken={..the csrftoken that you extracted in step 2..} see below

enter image description here 4- Post again

When you host django website on Apache server. Djando rest framework with TokenAuthentication and SessionAuthentication will get

CSRF Failed: CSRF token missing or incorrect

To fix this open Apache configuration file - httpd.conf Add following line:

WSGIPassAuthorization On
// USING AJAX TO UPDATE DATABASE THROUGH REST API
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}


var csrftoken = getCookie('csrftoken');


function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}


$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});

We had this problem and it turned out to be Postman's fault. They were automatically sending csrftoken and sessionid default values which we weren't passing in the header. Following this tutorial helped fix the issue: https://avilpage.com/2019/02/django-tips-csrf-token-postman-curl.html

The easiest way to solve this error, I found on here. It works for me perfectly.

Steps:

Inherit the SessionAuthentication class:

from rest_framework.authentication import SessionAuthentication, BasicAuthentication


class CsrfExemptSessionAuthentication(SessionAuthentication):


def enforce_csrf(self, request):
return  # To not perform the csrf check previously happening

Then in the APIView you have created, do this:

class Object(APIView):
authentication_classes = (CsrfExemptSessionAuthentication, BasicAuthentication)


def post(self, request, format=None):

This will keep you logged-in and your CSRF token will no longer be checked for this APIView.

django1.8 python2.7

{
"detail": "CSRF Failed: CSRF token missing or incorrect."
}

I fix it by using other httpmethod; oh, I face it again, this time is because I paste it, there are some invisible characters

I think it is a cookie issue.

Permanent Solution: If you are using Postman, First, clear the existing cookies by clicking 'X' s. Then add correct cookie.

Temporary Solution (for debugging): Try this in your settings.py:

'DEFAULT_AUTHENTICATION_CLASSES': [
# 'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
]

this happened to me while testing rest-auth registration using postman this happened because postman was sending incorrect headers some old cookies and wrong content type i think it is some kind of a bug or i was ding it wrong

Solution: so i disabled the default headers

manually entered content type and the json body(POST request)

then re-enabled the required headers

In settings.py file

INSTALLED_APPS = [
...
...
...
...
'rest_framework.authtoken',
...
]


REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
),
}


in project urls.py

from rest_framework.authtoken import views


urlpatterns = [
....
path('api-token-auth/',views.obtain_auth_token,name='api-token-auth')


]


Open terminal as

$ pip3 install httpie
$ python3 manage.py createsuperuser # if not created
$ http POST http://localhost:8000/api-token-auth/ username="username" password = "password"   # You will get token key (Just copy it) ex:a243re43fdeg7r4rfgedwe89320


You token key will be also automatically saved in your databases

Go to postman header (like in example) Ex: screenshot from postman ,where and how to paste accessed toke

Then insert you token key.

You can take reference to get token key from this video

The simplest solution that worked for me is:

Add CSRF token in the headers of the AJAX POST call, and this can be done by including this one line of code

headers: { "X-CSRFToken": '\{\{csrf_token}}' },

And this line should be added above the success

I faced same issue while testing API in postman, I solved it by cleaning cache in Postman for that request.