2011-06-28 17 views
46

trato de publicar parámetro como"CSRF token de falta o incorrecta" mientras que el parámetro posterior a través de AJAX en Django

jQuery.ajax(
     { 
      'type': 'POST', 
      'url': url, 
      'contentType': 'application/json', 
      'data': "{content:'xxx'}", 
      'dataType': 'json', 
      'success': rateReviewResult 
     } 
    ); 

Sin embargo, Django volver Forbidden 403. CSRF verification failed. Request aborted. estoy usando 'django.middleware.csrf.CsrfViewMiddleware' y no podía encontrar cómo puedo evitar que esto problema sin comprometer la seguridad.

+0

http://stackoverflow.com/questions/5100539/django-csrf-check-failing-with-an-ajax-post-request –

Respuesta

75

Puede hacer una petición AJAX después de dos formas diferentes:

  1. de decirle a su punto de vista no para comprobar el token CSRF. Esto se puede hacer mediante el uso de decorador @csrf_exempt, así:

    from django.views.decorators.csrf import csrf_exempt 
    
    @csrf_exempt 
    def your_view_name(request): 
        ... 
    
  2. para incrustar un token CSRF en cada petición AJAX, para jQuery que puede ser:

    $(function() { 
        $.ajaxSetup({ 
         headers: { "X-CSRFToken": getCookie("csrftoken") } 
        }); 
    }); 
    

    Cuando la función getCookie recupera token CSRF de las cookies Yo 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 has a plugin 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); 
    
+2

Es importante tener en cuenta que es 'X-CSRFToken' y no' X -CSRF-Token' que también se usa comúnmente – shangxiao

+2

El uso del decorador 'csrf_exempt' puede incurrir en problemas de seguridad ya que la protección de middleware estará desactivada. –

31

La forma más sencilla que he encontrado es para incluir el valor {{csrf_token}} en los datos :

jQuery.ajax(
    { 
     'type': 'POST', 
     'url': url, 
     'contentType': 'application/json', 
     'data': { 
      'content': 'xxx', 
      'csrfmiddlewaretoken': '{{ csrf_token }}', 
     }, 
     'dataType': 'json', 
     'success': rateReviewResult 
    } 
); 
+4

¿Qué sucede si Django no procesa su JavaScript? Supongo que realmente estarías en el arroyo. –

+3

La pregunta original indicaba que estaban usando 'django.middleware.csrf.CsrfViewMiddleware' y Django devolvía el error, por lo que creo que es bastante seguro suponer que Django está procesando la solicitud de AJAX. – jerrykan

+5

El problema es que Django no está templaizando el JS, solo las vistas HTML. –

22

Me tomó un tiempo entender qué hacer con the code que Daniel publicó. 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:

  1. Crear un archivo csrf.js

  2. Pega the code en el archivo csrf.js

  3. referencia el código de la plantilla que lo necesite

    <script type="text/javascript" src="{{ STATIC_PREFIX }}js/csrf.js"></script> 
    

Observe 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 %}.


Consejo avanzado: si está utilizando plantillas y tiene algo así como base.html donde se extienden desde, entonces sólo puede hacer referencia a la secuencia de comandos de allí y usted no tiene que preocuparse más ahí resto de su archivos. Por lo que yo entiendo, esto tampoco debería representar ningún problema de seguridad.

+3

Esto me ahorró horas de hacks. Camino simple y pitónico desde la Documentación de Django. – Pratyush

+0

Por 'el código' ¿te refieres exactamente a cada personaje dentro del fondo verde? Copio y pego y hice lo que me dijiste, pero aun así obtuve 403 de error prohibido. Tal vez las cosas han cambiado? – Philip007

+0

@ Philip007, sí, el fondo verde. Cambiaron el documento por [Django 1.5] (https://docs.djangoproject.com/en/1.5/ref/contrib/csrf/), sin embargo, no veo ninguna diferencia real en los códigos resultantes. Simplemente están dando una explicación más larga y la opción de usar jQuery. –

4

Gracias a todos por todas las respuestas. Estoy usando Django 1.5.1. Llego un poco tarde a la fiesta, pero aquí va.

Encontré que el enlace al Django project era 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 breve 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 de marzo de el año 2016

Mi acercamiento a este problema en los últimos años ha cambiado. Agrego el código a continuación (desde Django docs) 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');

4

que tiene el mismo problema ayer y pensaron que sería ayudar a la gente si había una forma sencilla de manejar, así que escribí un plugin de jQuery para ello: 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.

Así es como se usa:

1- incluirla:

<script src="path/to/jquery.js"></script> 
<script src="path/to/jquery.cookie.js"></script> 
<script src="path/to/jquery.djangocsrf.js"></script> 

2- activarlo en su código:

$.djangocsrf("enable"); 

Django siempre añadir el token en una cookie si su plantilla usa {% csrf_token %}. Para asegurarse de que siempre añade que incluso si usted no utiliza la etiqueta especial en su plantilla, utilice el decorador de @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.

2

Incluir x-csrftoken cabecera de modo buscado:

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', 

}); 
0

Si, después de leer otras respuestas, alguien todavía está luchando por favor, intente lo siguiente:

$.ajax({ 
      type: "POST", 
      beforeSend: function (request) 
      { 
       request.setRequestHeader("X-CSRF-TOKEN", "${_csrf.token}"); 
      }, 
      url: servlet_path, 
      data : data, 
      success : function(result) { 
      console.log("Success!"); 
    } 
}); 
+0

. No pude hacer que funcione como se describe aquí. ¿Algunas ideas? ¿Parece que la propiedad 'beforeSend' no está tomando el token correctamente ...? – natureminded

3

A falta de una respuesta directa, sólo hay para agregar el encabezado X-CSRFToken a la solicitud ajax que está en la cookie csrftoken.JQuery no hace galletas (por alguna razón) sin a plugin manera:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script> 

y el cambio de código mínimo es:

$.ajax({ 
    headers: { "X-CSRFToken": $.cookie("csrftoken") }, 
    ... 
}); 
+0

mil votos hombre ..... siempre me pregunto por qué la gente simplemente no puede hacer una respuesta simple como esta !! – NoobEditor

2

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}}'); 
    } 
    } 
}); 

docs

Cuestiones relacionadas