csrfmiddlewaretoken - "Falta el token de CSRF o es incorrecto", mientras que el parámetro de publicación a través de AJAX en Django
get csrf token django (9)
Intento publicar un parámetro como
jQuery.ajax(
{
''type'': ''POST'',
''url'': url,
''contentType'': ''application/json'',
''data'': "{content:''xxx''}",
''dataType'': ''json'',
''success'': rateReviewResult
}
);
Sin embargo, Django devuelve Forbidden 403. CSRF verification failed. Request aborted.
Forbidden 403. CSRF verification failed. Request aborted.
Estoy usando ''django.middleware.csrf.CsrfViewMiddleware''
y no pude encontrar cómo puedo evitar este problema sin comprometer la seguridad.
A falta de una respuesta directa, solo tiene que agregar el encabezado X-CSRFToken
a la solicitud ajax que está en la cookie csrftoken
. JQuery no hace cookies (por alguna razón) sin un plugin así que:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
y el cambio mínimo de código es:
$.ajax({
headers: { "X-CSRFToken": $.cookie("csrftoken") },
...
});
Ayer recibí el mismo problema y pensé que ayudaría a las personas si hubiera una forma sencilla de manejarlo, así que escribí un complemento jQuery para eso: jquery.djangocsrf . En lugar de agregar el token CSRF en cada solicitud, se engancha en el evento AjaxSend jQuery y agrega la cookie del cliente en un encabezado.
He aquí cómo usarlo:
1- incluirlo:
<script src="path/to/jquery.js"></script>
<script src="path/to/jquery.cookie.js"></script>
<script src="path/to/jquery.djangocsrf.js"></script>
2- habilitarlo en tu código:
$.djangocsrf( "enable" );
Django siempre agrega el token en una cookie si su plantilla usa {% csrf_token %}
. Para asegurarse de que siempre lo agregue, incluso si no usa la etiqueta especial en su plantilla, use el decorador @ensure_csrf_cookie
:
from django.views.decorators.csrf import ensure_csrf_cookie
@ensure_csrf_cookie
def my_view(request):
return render(request, ''mytemplate.html'')
Nota: estoy usando Django 1.6.2.
Gracias a todos por todas las respuestas. Estoy usando Django 1.5.1. Llego un poco tarde a la fiesta, pero aquí va.
Encontré el enlace al proyecto Django muy útil, pero realmente no quería tener que incluir el código JavaScript adicional cada vez que quería hacer una llamada Ajax.
Me gusta la respuesta de Jerrykan, ya que es muy sucinta y solo agrega una línea a una llamada Ajax normal. En respuesta a los comentarios que aparecen debajo de su comentario sobre situaciones en las que las etiquetas de plantilla de Django no están disponibles, ¿qué le parece cargar el archivo csrfmiddlewaretoken del DOM?
var token = $(''input[name="csrfmiddlewaretoken"]'').prop(''value'');
jQuery.ajax({
type: ''POST'',
url: url,
data: { ''csrfmiddlewaretoken'': token },
dataType: ''json'',
success: function(data) { console.log(''Yippee! '' + data); }
});
EDITAR Marzo de 2016
Mi enfoque sobre este tema en los últimos años ha cambiado. Agrego el código a continuación (desde los documentos de Django ) a un archivo main.js y lo cargo en cada página. Una vez hecho esto, no debería tener que preocuparse por el token CSRF con ajax nuevamente.
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]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + ''='')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie(''csrftoken'');
Incluya el encabezado x-csrftoken
en la solicitud:
var token = $(''input[name="csrfmiddlewaretoken"]'').prop(''value'');
jQuery.ajax({
type: ''POST'',
url: url,
beforeSend : function(jqXHR, settings) {
jqXHR.setRequestHeader("x-csrftoken", get_the_csrf_token_from_cookie());
},
data: data,
dataType: ''json'',
});
La forma más sencilla que he encontrado es incluir el valor de {{csrf_token}}
en los datos:
jQuery.ajax(
{
''type'': ''POST'',
''url'': url,
''contentType'': ''application/json'',
''data'': {
''content'': ''xxx'',
''csrfmiddlewaretoken'': ''{{ csrf_token }}'',
},
''dataType'': ''json'',
''success'': rateReviewResult
}
);
Me tomó un tiempo entender qué hacer con el código que publicó Daniel. Pero en realidad todo lo que tienes que hacer es pegarlo al comienzo del archivo javascript.
Para mí, la mejor solución hasta ahora es:
Cree un archivo
csrf.js
Pegue el código en el archivo
csrf.js
Haga referencia al código en la plantilla que lo necesita
<script type="text/javascript" src="{{ STATIC_PREFIX }}js/csrf.js"></script>
Tenga en cuenta que STATIC_PREFIX/js/csrf.js
apunta a mi archivo. De hecho, estoy cargando la variable STATIC_PREFIX
con {% get_static_prefix as STATIC_PREFIX %}
.
base.html
avanzado: si está usando plantillas y tiene algo como base.html
donde se extiende, entonces puede simplemente hacer referencia al script desde allí y ya no tendrá que preocuparse por el resto de sus archivos. Por lo que yo entiendo, esto tampoco debería representar ningún problema de seguridad.
Puede realizar la solicitud de publicación de AJAX de dos maneras diferentes:
Para decirle a su vista que no verifique el token csrf. Esto se puede hacer usando el decorador
@csrf_exempt
, así:from django.views.decorators.csrf import csrf_exempt @csrf_exempt def your_view_name(request): ...
Para incrustar un token csrf en cada solicitud AJAX, para jQuery puede ser:
$(function () { $.ajaxSetup({ headers: { "X-CSRFToken": getCookie("csrftoken") } }); });
Donde la función
getCookie
recupera el token csrf de las cookies. Uso la siguiente implementación:function getCookie(c_name) { if (document.cookie.length > 0) { c_start = document.cookie.indexOf(c_name + "="); if (c_start != -1) { c_start = c_start + c_name.length + 1; c_end = document.cookie.indexOf(";", c_start); if (c_end == -1) c_end = document.cookie.length; return unescape(document.cookie.substring(c_start,c_end)); } } return ""; }
Además, jQuery tiene un complemento para acceder a las cookies, algo así:
// set cookie $.cookie(''cookiename'', ''cookievalue'');<br> // read cookie var myCookie = $.cookie(''cookiename'');<br> // delete cookie $.cookie(''cookiename'', null);
Si, después de leer otras respuestas, alguien sigue teniendo dificultades, intente esto:
$.ajax({
type: "POST",
beforeSend: function (request)
{
request.setRequestHeader("X-CSRF-TOKEN", "${_csrf.token}");
},
url: servlet_path,
data : data,
success : function(result) {
console.log("Success!");
}
});
Simple y corto
$.ajaxSetup({
headers: { "X-CSRFToken": ''{{csrf_token}}'' }
});
O
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", ''{{csrf_token}}'');
}
}
});