403 Error prohibido al realizar una solicitud de publicación de Ajax en el marco Django

Intento integrar jquery en una aplicación web que estoy creando con Django framework. Sin embargo, estoy teniendo dificultades para intentar hacer una simple llamada ajax al trabajo. Mi archivo de plantilla que contiene el formulario html y javascript para manejar la llamada ajax se ve así:

  $(document).ready(function() { $( "#target" ).submit(function() { console.log('Form was submitted'); $.ajax({ type: "POST", url: "/hello/", // or just url: "/my-url/path/" data: { query: $( "#query" ).val() }, success: function(data) { console.log(data); } }); return false; }); })  
{% csrf_token %}

Mi views.py que se supone maneja la llamada ajax se ve así:

  from django.core.context_processors import csrf from django.shortcuts import render_to_response from django.template.loader import get_template from django.template import Context,RequestContext from django.views.decorators.csrf import ensure_csrf_cookie from django.http import HttpResponse # access resource def hello(request): c = {} c.update(csrf(request)) if request.is_ajax(): t = get_template('template.html') #html = t.render(Context({'result': 'hello world'})) con = RequestContext(request, {'result': 'hello world'}) return render_to_response('template.html', c, con) else: return HttpResponse('Not working!') 

Intenté seguir la documentación oficial sobre Protección contra falsificación de solicitudes entre sitios y también analicé varias preguntas sobre el flujo de datos que abordaban un problema similar. He incluido el {% csrf_token %} en mi archivo de plantilla html , pero parece que todavía no funciona. Aparece un error en la consola que sugiere que la llamada ajax falló:

 POST http://127.0.0.1:8000/hello/ 403 (FORBIDDEN) 

¿Cómo paso la variable de result junto con mi respuesta http y consigo que la llamada ajax funcione sin problemas? Cualquier ayuda es muy apreciada.

Edit-1

Supuestamente no estaba pasando el token csrf junto con mi solicitud posterior. ASÍ, según la documentación, agregué el siguiente código a mi plantilla javascript:

 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'); console.log(csrftoken); //Ajax call function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ crossDomain: false, // obviates need for sameOrigin test beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type)) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } }); 

Cuando actualizo la página html de la plantilla en el navegador, obtengo un null en la consola, lo que sugiere que la cookie no está configurada o no está definida. ¿Qué me estoy perdiendo?

Como no has publicado el csrfmiddlewaretoken , Django te lo prohíbe. este documento puede ayudarte.

Para los chicos perezosos:

Primera cookie de descarga: http://plugins.jquery.com/cookie/

Añádelo a tu html:

  

Ahora puedes crear una solicitud POST funcional:

 var csrftoken = $.cookie('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); } } }); $.ajax(save_url, { type : 'POST', contentType : 'application/json', data : JSON.stringify(canvas), success: function () { alert("Saved!"); } }) 

Encuentro todas las respuestas anteriores en el lugar, pero pongamos las cosas en contexto.

La 403 respuesta prohibida proviene del middleware de CSRF (ver Protección de falsificación de solicitudes entre sitios ):

De forma predeterminada, se envía una respuesta ‘403 Prohibida’ al usuario si una solicitud entrante falla las comprobaciones realizadas por CsrfViewMiddleware.

Muchas opciones están disponibles. Yo recomendaría seguir la respuesta de @fivef para hacer que jQuery agregue el encabezado X-CSRFToken antes de cada solicitud AJAX con $.ajaxSetup .

Esta respuesta requiere el plugin cookie jQuery. Si esto no es deseable, otra posibilidad es agregar:

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

PERO: si la configuración CSRF_COOKIE_HTTPONLY se establece en True, lo que a menudo ocurre cuando el middleware Security lo recomienda, entonces la cookie no está allí, incluso si se usa @ensure_csrf_cookie() . En este caso, se debe proporcionar {% csrf_token %} en cada forma, lo que produce una salida como . Entonces la variable csrfToken simplemente se obtendría con:

 var csrftoken = $('input[name="csrfmiddlewaretoken"]').val(); 

Nuevamente se $.ajaxSetup por supuesto.

Otras opciones disponibles pero no recomendadas son desactivar el middleware o la protección csrf para el formulario específico con @csrf_exempt() .

Para configurar la cookie, use el decorador ensure_csrf_cookie en su vista:

 from django.views.decorators.csrf import ensure_csrf_cookie @ensure_csrf_cookie def hello(request): code_here() 

Asegúrese de que no está almacenando en caché la página / vista en la que se muestra su formulario. Podría estar almacenando en caché tu CSRF_TOKEN. ¡Me sucedió!

Intenta incluir este decorador en tu código de envío

 from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt @method_decorator(csrf_exempt, name='dispatch') def dispatch(self, request, *args, **kwargs): return super(LessonUploadWorkView,self).dispatch(request,*args,**kwargs) 

Con SSL / https y con CSRF_COOKIE_HTTPONLY = False, todavía no tengo csrftoken en la cookie, ya sea usando la función getCookie (nombre) propuesta en django Doc o la jquery.cookie.js propuesta por fivef .

El resumen de Wtower es perfecto y pensé que funcionaría después de eliminar CSRF_COOKIE_HTTPONLY de settings.py pero no funciona en https.

¿Por qué csrftoken no está visible en document.cookie?

En lugar de conseguir

“django_language = fr; csrftoken = rDrGI5cp98MnooPIsygWIF76vuYTkDIt”

Solo obtengo

“django_language = fr”

¿POR QUÉ? Al igual que SSL / https elimina X-CSRFToken de los encabezados , pensé que se debía a los parámetros del encabezado proxy de Nginx, pero aparentemente no … ¿Alguna idea?

A diferencia de las notas de django doc , parece imposible trabajar con csrf_token en las cookies con https. La única forma de pasar csrftoken es a través del DOM usando {% csrf_token%} en html y obtenerlo en jQuery usando

 var csrftoken = $('input[name="csrfmiddlewaretoken"]').val(); 

Entonces es posible pasarlo a ajax por encabezado ( xhr.setRequestHeader ), ya sea por params .

La solución más rápida si no está incorporando js en su plantilla es:

Pon antes de su referencia al archivo script.js en su plantilla, luego agregue csrfmiddlewaretoken en su diccionario de data :

 $.ajax({ type: 'POST', url: somepathname + "do_it/", data: {csrfmiddlewaretoken: window.CSRF_TOKEN}, success: function() { console.log("Success!"); } }) 

Si incrusta su js en la plantilla, es tan simple como: data: {csrfmiddlewaretoken: '{{ csrf_token }}'}

Debe cambiar su carpeta chmod 755 y file (.php, .html) chmod 644.