403 Erro proibido ao fazer uma solicitação Post ajax no framework Django

Eu estou tentando integrar jquery em um aplicativo da web que estou fazendo com o framework Django. No entanto, estou tendo dificuldade em fazer uma simples chamada do ajax para o trabalho. Meu arquivo de modelo que contém o formulário html e javascript para lidar com a chamada ajax se parece com:

  $(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 %}    

Meu views.py que supostamente cuida da chamada ajax se parece com:

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

Eu tentei seguir a documentação oficial sobre Cross-Site Request Forgery Protection e também olhei para várias questões de stackoverflow abordando um problema similar. Eu incluí o {% csrf_token %} no meu arquivo de modelo html mas ainda não parece estar funcionando. Eu recebo um erro no console sugerindo que a chamada do ajax falhou:

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

Como faço para passar a variável de result junto com minha resposta http e obter a chamada ajax para funcionar sem problemas? Qualquer ajuda é profundamente apreciada.

Edit-1

Eu não estava supostamente passando o token csrf junto com o meu pedido de postagem. SO conforme a documentação eu adicionei o seguinte código ao meu template 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); } } }); 

Quando atualizo a página template html no navegador, obtenho null no console, sugerindo que o cookie não está definido ou não definido. o que estou perdendo?

Porque você não postou o csrfmiddlewaretoken , então o Django proíbe você. este documento pode ajudá-lo.

Para os caras preguiçosos:

Primeiro cookie de download: http://plugins.jquery.com/cookie/

Adicione ao seu html:

  

Agora você pode criar uma solicitação POST de trabalho:

 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!"); } }) 

Eu encontro todas as respostas anteriores no local, mas vamos colocar as coisas no contexto.

A resposta 403 proibida vem do middleware CSRF (consulte Proteção de falsificação de solicitação de site cruzado ):

Por padrão, uma resposta ‘403 Proibida’ é enviada ao usuário se uma solicitação recebida falhar nas verificações realizadas pelo CsrfViewMiddleware.

Muitas opções estão disponíveis. Eu recomendaria seguir a resposta de @fivef para fazer com que o jQuery adicione o header X-CSRFToken antes de cada requisição AJAX com $.ajaxSetup .

Essa resposta requer o cookie do plugin jQuery. Se isso não é desejável, outra possibilidade é adicionar:

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

MAS: se a configuração CSRF_COOKIE_HTTPONLY estiver definida como True, o que geralmente acontece como o middleware de segurança recomenda, o cookie não está lá, mesmo se @ensure_csrf_cookie() for usado. Nesse caso, {% csrf_token %} deve ser fornecido em todos os formulários, o que produz uma saída como . Então a variável csrfToken seria simplesmente obtida com:

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

Mais uma vez, $.ajaxSetup seria necessário, é claro.

Outras opções disponíveis, mas não recomendadas, são desativar o middleware ou a proteção csrf para o formulário específico com @csrf_exempt() .

Para definir o cookie, use o decorador ensure_csrf_cookie na sua visualização:

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

Verifique se você não está armazenando em cache a página / visualização em que seu formulário está sendo exibido. Pode estar armazenando em cache o seu CSRF_TOKEN. Aconteceu comigo!

Tente include este decorador no seu código de expediçã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) 

Com SSL / https e com CSRF_COOKIE_HTTPONLY = False, eu ainda não tenho csrftoken no cookie, seja usando a function getCookie (name) proposta no django Doc ou o jquery.cookie.js proposto por fivef .

O resumo da Wtower é perfeito e eu pensei que funcionaria depois de remover CSRF_COOKIE_HTTPONLY de settings.py mas ele não está em https!

Por que o csrftoken não é visível em document.cookie ???

Em vez de ficar

“django_language = fr; csrftoken = rDrGI5cp98MnooPIsygWIF76vuYTkDIt”

Eu só tenho

“django_language = fr”

PORQUE? Como SSL / https remove X-CSRFToken de headers Eu pensei que era devido aos params de header proxy do Nginx, mas aparentemente não … Alguma idéia?

Ao contrário do django doc Notes , parece impossível trabalhar com csrf_token em cookies com https. A única maneira de passar o csrftoken é através do DOM usando {% csrf_token%} em html e obtê-lo no jQuery usando

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

É então possível passá-lo para ajax pelo header ( xhr.setRequestHeader ), seja por params .

A solução mais rápida se você não estiver embutindo js no seu template é:

Coloque antes de sua referência ao arquivo script.js em seu modelo, em seguida, adicione csrfmiddlewaretoken ao seu dictionary de data :

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

Se você inserir seus js no modelo, é tão simples quanto: data: {csrfmiddlewaretoken: '{{ csrf_token }}'}

Você deve alterar sua pasta chmod 755 e arquivo (.php, .html) chmod 644.