Ich versuche, Jquery in eine Webanwendung zu integrieren, die ich mit Django Framework mache. Es fällt mir jedoch schwer, einen einfachen Aufruf von ajax
zur Arbeit zu machen. Meine Vorlagendatei, die das Formular html und javascript enthält, um den Ajax-Aufruf abzuwickeln, sieht folgendermaßen aus:
<script type="text/javascript">
$(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;
});
})
</script>
<form id="target" action="." method="post">{% csrf_token %}
<input id= "query" type="text" value="Hello there">
<input type="submit" value="Search Recent Tweets">
</form>
Mein views.py
, der den Ajax-Aufruf behandeln soll, sieht folgendermaßen aus:
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!')
Ich habe versucht, der offiziellen Dokumentation zu Cross-Site Request Forgery Protection zu folgen, und habe mir auch mehrere Stackoverflow-Fragen angesehen, die ein ähnliches Problem ansprechen. Ich habe den {% csrf_token %}
in meine html
-Vorlagendatei aufgenommen, aber es scheint immer noch nicht zu funktionieren. In der Konsole wird eine Fehlermeldung angezeigt, die darauf hinweist, dass der Ajax-Aufruf fehlgeschlagen ist:
POST http://127.0.0.1:8000/hello/ 403 (FORBIDDEN)
Wie übergebe ich die Variable result
zusammen mit meiner http-Antwort und den ajax-Aufruf zum reibungslosen Funktionieren bringen? Jede Hilfe wird sehr geschätzt.
Edit-1
Ich habe angeblich nicht das csrf
-Token zusammen mit meiner Post-Anfrage übergeben. SO Wie in der Dokumentation angegeben, fügte ich meinem Template-Javascript den folgenden Code hinzu:
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);
}
}
});
Wenn ich die HTML-Vorlagenseite im Browser aktualisiere, erhalte ich in der Konsole null
, was darauf hindeutet, dass das Cookie nicht gesetzt oder definiert ist. Was vermisse ich?
Da Sie das csrfmiddlewaretoken nicht gepostet haben, verbietet Django Ihnen das ... _. dieses Dokument kann Ihnen helfen.
Für die faulen Jungs:
Laden Sie zuerst den Cookie herunter: http://plugins.jquery.com/cookie/
Fügen Sie es Ihrer HTML-Datei hinzu:
<script src="{% static 'designer/js/jquery.cookie.js' %}"></script>
Jetzt können Sie eine funktionierende POST - Anforderung erstellen:
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!");
}
})
Ich finde alle vorherigen Antworten vor Ort, aber stellen wir die Dinge in einen Kontext.
Die 403-verbotene Antwort stammt von der CSRF-Middleware (siehe Cross Site Request Forgery-Schutz ):
Standardmäßig wird dem Benutzer eine Antwort "403 Forbidden" gesendet, wenn eine eingehende Anforderung die von CsrfViewMiddleware durchgeführten Prüfungen nicht besteht.
Viele Optionen stehen zur Verfügung. Ich würde empfehlen, der Antwort von @fivef zu folgen, damit jQuery vor jeder AJAX - Anforderung mit X-CSRFToken
den $.ajaxSetup
-Header hinzufügt.
Diese Antwort erfordert das Cookie-Plugin jQuery. Wenn dies nicht erwünscht ist, besteht die Möglichkeit, Folgendes hinzuzufügen:
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');
ABER: Wenn die Einstellung CSRF_COOKIE_HTTPONLY
auf True gesetzt ist, was oft als Security-Middleware empfohlen wird, ist der Cookie nicht vorhanden, selbst wenn @ensure_csrf_cookie()
verwendet wird. In diesem Fall muss {% csrf_token %}
in jedem Formular angegeben werden, das eine Ausgabe wie <input name="csrfmiddlewaretoken" value="cr6O9...FUXf6" type="hidden">
erzeugt. Die Variable csrfToken
würde also einfach erhalten mit:
var csrftoken = $('input[name="csrfmiddlewaretoken"]').val();
Natürlich wäre wieder $.ajaxSetup
erforderlich.
Andere Optionen, die verfügbar sind, aber nicht empfohlen sind, die Middleware oder den csrf-Schutz für das spezifische Formular mit @csrf_exempt()
zu deaktivieren.
Verwenden Sie zum Festlegen des Cookies den Dekorator ensure_csrf_cookie
in Ihrer Ansicht:
from Django.views.decorators.csrf import ensure_csrf_cookie
@ensure_csrf_cookie
def hello(request):
code_here()
Stellen Sie sicher, dass Sie die Seite/Ansicht nicht zwischenspeichern, auf der Ihr Formular angezeigt wird. Es könnte sein, dass Sie Ihren CSRF_TOKEN zwischenspeichern. Passierte mir!
data: {"csrfmiddlewaretoken" : "{{csrf_token}}"}
Sie sehen "403 (FORBIDDEN)", weil Sie den Parameter "csrfmiddlewaretoken" nicht senden. In der Vorlage hat jedes Formular Folgendes: {% csrf_token%}. Sie sollten "csrfmiddlewaretoken" zu Ihrem Ajax-Datenwörterbuch hinzufügen. Mein Beispiel sendet "product_code" und "csrfmiddlewaretoken" an die App "basket" view "remove":
$(function(){
$('.card-body').on('click',function(){
$.ajax({
type: "post",
url: "{% url 'basket:remove'%}",
data: {"product_code": "07316", "csrfmiddlewaretoken" : "{{csrf_token}}" }
});
})
});
Die schnellste Lösung, wenn Sie js nicht in Ihre Vorlage einbetten, ist:
Fügen Sie <script type="text/javascript"> window.CSRF_TOKEN = "{{ csrf_token }}"; </script>
vor Ihrem Verweis auf die Datei script.js in Ihre Vorlage ein und fügen Sie dann csrfmiddlewaretoken
in Ihr data
-Wörterbuch ein:
$.ajax({
type: 'POST',
url: somepathname + "do_it/",
data: {csrfmiddlewaretoken: window.CSRF_TOKEN},
success: function() {
console.log("Success!");
}
})
Wenn Sie Ihre Js in die Vorlage einbetten, ist es so einfach: data: {csrfmiddlewaretoken: '{{ csrf_token }}'}
Versuchen Sie, diesen Dekorator in Ihren Versandcode aufzunehmen
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)
Mit SSL/https und mit CSRF_COOKIE_HTTPONLY = False habe ich immer noch kein csrftoken im Cookie, entweder mit der Funktion getCookie (name), die in Django Doc oder der jquery) vorgeschlagen wird. cookie.js vorgeschlagen von fivef .
Wtower Die Zusammenfassung ist perfekt und ich dachte, es würde funktionieren, nachdem ich CSRF_COOKIE_HTTPONLY aus den settings.py entfernt habe, aber nicht in https!
Warum ist csrftoken in document.cookie nicht sichtbar ???
Anstatt zu bekommen
"Django_language = fr; csrftoken = rDrGI5cp98MnooPIsygWIF76vuYTkDIt"
Ich bekomme nur
"Django_language = fr"
WARUM? Wie SSL/https entfernt X-CSRFToken aus den Kopfzeilen Ich dachte, es lag an den Proxy-Header-Params von Nginx, aber anscheinend nicht ... Irgendeine Idee?
Im Gegensatz zu Django doc Notes scheint es nicht möglich zu sein, mit csrf_token in Cookies mit https zu arbeiten. Die einzige Möglichkeit, csrftoken zu übergeben, besteht im DOM, indem Sie {% csrf_token%} in html verwenden und es in jQuery mithilfe von erhalten
var csrftoken = $('input[name="csrfmiddlewaretoken"]').val();
Es ist dann möglich, es an ajax entweder über einen Header ( xhr.setRequestHeader ) oder über params zu übergeben.