Invalid CSRF or Missing Token in DJango - python

I have already checked this link on Stackoverflow but still facing same issue: CSRF verification failed. Request aborted. on django
About the issue
I am trying to submit ajax request to DJango.
Html Form
<form id="frmLogin" method="post">
{% csrf_token %}
<input type="text" name="username" />
<input type="password" autocomplete="false" name="password" />
<input type="submit" value="Submit" />
</form>
Ajax
$("form#frmLogin").validate({
rules: {
username: {
required: true
},
password: {
required: true
}
},
submitHandler: function(form) {
var data = {
"username": $(form).find("input[name='username']").val(),
"password": $(form).find("input[name='password']").val(),
"csrfmiddlewaretoken": $(form).find("input[name='csrfmiddlewaretoken']").val()
};
$.ajax({
method: "POST",
url: "/authenticate/",
cache: false,
async: true,
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
success: function(response) {
//$(form).remove();
}
})
}
});
View
from django.shortcuts import render
import json
from django.http import JsonResponse
def Authenticate(request):
if request.method == "POST":
#loginData = json.loads(request.body)
#email = userData["email"]
#password = userData["password"]
print("ok")
return JsonResponse({}, status = 200)
else:
print("not ok")
Payload Info
Error Message
Am I missing anything?

You need to add CSRF_TRUSTED_ORIGINS in settings.py file and add your origin to it as a trusted origin for unsafe requests like (POST request ) like this :
CSRF_TRUSTED_ORIGINS = ['https://your-domain.com']

Following block need to be passed to add headers to make POST request successful.
beforeSend: function(xhr, opts) {
xhr.setRequestHeader('X-CSRFToken', $(form).find("input[name='csrfmiddlewaretoken']").val());
}

Related

Ajax form not sending data in django

I am trying to send data to Django without page refresh. So I am using ajax.
Created a Django model and form
class MyModel(models.Model):
text=models.CharField(max_length=100)
class MyForm(forms.ModelForm):
class Meta:
model=MyModel
fields = "__all__"
Then send the form to the HTML page via views.py
def home(request):
print(request.POST.get('text',False))
form = MyForm(request.POST)
if request.method=='POST':
print(request.POST.get('text',False))
if form.is_valid():
data=form.save()
return render(request,'home.html',{'form':form})
Create a form in HTML template
<form action = "" id="post-form" method = "post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="submit" id="submit-button">
</form>
This is the javascript file
$(document).on('submit','#post-form',
function(x){
x.preventDefault();
console.log("button clicked")
$.ajax({
type:'POST',
url:'/',
data:{
text:$("id_text").val(),
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val()
},
success:function(){
alert('Saved');
}
})
}
)
I think it might be the issue with URL, if i set url like this way
url:'{% url "home" %}',
Then in console, i got this error
XHR POST http://127.0.0.1:8000/%7B%%20url%20%22home%22%20%%7D
I am unable to find, where is the issue.
You should use # for selecting id, so use text:$("#id_text").val().
For using dynamic url, use like this:
url:"{% url 'home' %}",
For more information, about using dynamic urls refer this question.
Edit:
One way to use dynamic url is to pass it with onsubmit event, so try this:
Template file or home.html
<form id="post-form" method="POST" onsubmit="checking('{% url 'home' %}')">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="submit" id="submit-button">
</form>
Js file:
function checking(dynamicUrl) {
$(document).on("submit", "#post-form", function (x) {
x.preventDefault();
console.log("button clicked");
$.ajax({
type: "POST",
url: dynamicUrl,
data: {
text: $("#id_text").val(),
csrfmiddlewaretoken: $("input[name=csrfmiddlewaretoken]").val(),
},
success: function () {
alert("Saved");
},
});
});
}

Python Flask ajax POST 400 BAD REQUEST

I am trying to send data from a form to Python Flask using ajax. I do not want the page to reload. When I try to send the form I get the error
POST http://127.0.0.1:5000/addTran 400 (BAD REQUEST)
I just want to input a Russian word with an English translation and then to write it to a file from flask.
Here is my html and JavaScript
<form id="translationForm">
<label for="russianWord">Russian Word:</label><br>
<input type="text" id="russianWord" serialize-as="russianWord" name="russianWord"><br>
<label for="englishWord">English word:</label><br>
<input type="text" id="englishWord" serialize-as="englishWord" name="englishWord">
<input type="submit" value="Submit">
</form>
<script>
$(function () {
$('#translationForm').on('submit',function (e) {
$.ajax({
type: 'POST',
url: "{{url_for('addTran')}}",
data: $('#translationForm').serialize(),
contentType: "application/j-son;charset=UTF-8",
dataType: "json",
success: function () {
alert("It worked!");
}
});
e.preventDefault();
});
});
Here is my Python route
#app.route('/addTran',methods=["POST"])
def addTran():
if request.method == "POST":
tran = request.get_json(force=True)
with open('/home/matt/Desktop/info.txt','w') as w:
w.write(str(tran))
Adding JSON.stringify() worked!
data: JSON.stringify($('#translationForm').serialize())
Maybe it's the typo in the request content type?
contentType: "application/j-son;charset=UTF-8",
To
contentType: "application/json",

How Can I send json file by ajax to django?

Can I send .json with data like (login,password from input html) to django who download this file and check login/password? Then I want return results by django to js,jquery. I dont wan use forms-django in form-html and dont want change urls.
code html:
<form id='login_form' action="" method="POST">
{% csrf_token %}
<div id='Login_form'>
<p>Login: </p> <input type="text" onblur="CheckEmptyElements();" id="flogin">
<p>Password: </p> <input type="password" onblur="CheckEmptyElements();" id="lpass">
<div id="butt_form">
<button type="button" class="butt_forme" id="button" onclick="CheckBeforeSend();">Enter</button>
</div>
</div>
</form>
code js:
var LoginInput = document.getElementById('flogin');
if(LoginInput.value.match(/^[a-zA-Z]+['.']+[a-zA-Z]+[0-9]+$/) == null)
{
if(document.getElementById('Windows').childElementCount > 2)
{
document.getElementById('Windows').children[0].remove();
}
AddPicture("paperJsConn");
}
else // <--- Check login/pass in base django
{
document.getElementById("button").type = "submit";
$.ajax({
type:"POST",
url: '',
data: {
"login":
"password":
},
success: function(response){
//animation and change site if correct login/pass or reloaded site.
}
});
}
and views.py:
def Logget(request):
if request.is_ajax and request.method == "POST":
//take login from json and check in base by loop
//if find check password
if: // correct
// return .json or message that is correct.
else:
// return .json or message that is not correct.
return render(request, 'index.html')
Someone help please?

How to make cross-domain Ajax calls with CSRF token?

I have a typical login form in my Django app template (which uses Bootstrap directly, not through some plugin):
<form class="form-signin" method="post" action="/site_manager/login/" id="form-signin"> {% csrf_token %}
<h2 class="form-signin-heading">Please sign in</h2>
<div class="control-group">
<label class="control-label" for="login">Login:</label>
<div class="controls">
<input size="50" name="username" id="username" required="true" type="text" class="form-control" placeholder="Login" intermediateChanges=false>
</div>
</div>
<div class="control-group">
<label class="control-label" for="password">Password:</label>
<div class="controls">
<input size="50" name="password" id="password" required="true" type="password" class="form-control" placeholder="Password" intermediateChanges=false>
</div>
</div>
<button name="submit" id="submit" value="Log in" type="submit" class="btn btn-primary pull-right">Sign in</button>
</form>
And here is the corresponding view which performs remote authentication through the requests module:
def login_view(request):
if request.POST:
username = request.POST.get('username')
password = request.POST.get('password')
headers = {'content-type': 'application/json', 'username':username, 'password':password}
r = requests.get(remote_server_url, auth=(username, password), headers=headers)
if r.status_code == 200:
user = authenticate(username=username, password=password)
if user == None:
user = User.objects.create_user(username.encode('ascii', 'ignore'), "", password)
user = authenticate(username=username, password=password)
login(request, user)
request.session.set_expiry(0)
return HttpResponseRedirect('<index_page>')
else:
# redirects back to login page with some error message
Once this login succeeds, I can query the CSRF token with Javascript, as explained here, and my plan is to make Ajax calls to the remote server (over SSL) for other purposes (RESTful queries, for example). That server, as the above code suggests, uses basic authentication. So I want to set the CSRF token in the header of every Ajax call, but this does not follow the same-origin principle:
var csrftoken = $.cookie('csrftoken'); // using the jQuery Cookie plugin
$.ajaxSetup({
headers: {
'Authorization': "Basic XXXXX"
}
beforeSend: function(xhr, settings) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
});
$.ajax({
type: "GET",
dataType: "jsonp",
url: remote_server_url+'/api/v1/someRESTfulResource/',
contentType: 'application/json',
success: function(data){
// some operations with data
}
});
The remote_server_url used in the Ajax call and the authentication are the same, and it does not share the same domain with the Django application. It is a security risk, as I gather. I also do not want to make plain text password available in the Javascript code for the same reason. How could I make Ajax calls to the remote server with the user credentials securely?
I am doing this on my Javascript initialization for a page I want to do Ajax POSTS with django:
$(document).ajaxSend(function(event, xhr, settings) {
function sameOrigin(url) {
// url could be relative or scheme relative or absolute
var host = document.location.host; // host + port
var protocol = document.location.protocol;
var sr_origin = '//' + host;
var origin = protocol + sr_origin;
// Allow absolute or scheme relative URLs to same origin
return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
(url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
// or any other URL that isnt scheme relative or absolute i.e relative.
!(/^(\/\/|http:|https:).*/.test(url));
}
function safeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
xhr.setRequestHeader("X-CSRFToken", '{{ csrf_token }}');
}
});
I don't remember where I've found it, however after using it I can do Ajax posts like this:
$.post("{% url 'foo' %}", "data="+myjson, function(data) {
if(data['result']=="ok") {
window.location.replace('{% url "bar" %}');
} else {
alert("Data Err!");
}
}).error(function() {
alert("Ajax error!");
});

How can I catch server json response while uploading image using Ajax?

I have a form which is loaded via jQuery from the external template file:
$('#imguploadform').html(' ').load('{% url upload_form %}');
In template it looks like this:
<img src="{{ MEDIA_URL }}img/misc/upload.png" alt="Illustration" title="myimage" />
<form id="uploadForm" enctype="multipart/form-data" method="post" action="upload_picture/">
{{ form.as_ul }}
<input type="submit" value="Upload" id="uploadImage" />
</form>
I'm trying to upload an image with ajax using jquery form plugin:
var submit_options = {
target: '#picworks',
dataType: 'json',
success: function() {
alert('It Works!');
}
};
$('#uploadForm').submit(function(){
$(this).ajaxSubmit(submit_options);
return false;
});
But then I want to return a json object from server and dynamically load into page an image using it's returned address. I've tried like this:
def upload_picture(request):
dest = save_original(request.FILES['image'])
form = UploadImageForm(request.POST, request.FILES)
res = json.dumps({
"path": dest,
})
return HttpResponse(res, mimetype='application/json')
The problem is that I can't catch a json response in javascript, so my browser shows me just an empty page with json dictionary content. What I'm doing wrong?
Have your success callback take a parameter. That will be the response.
var submit_options = {
target: '#picworks',
dataType: 'json',
success: function(response) {
alert('It Works!');
window.location.href = response.path;
}
};
I solved the problem! The thing is that function which replace form submitting action with an ajax request is called earlier than the form loads from external file. So it should be like this:
$('#imguploadform').html(' ').load('{% url upload_form %}',
function(){
var submit_options = {
dataType: 'json',
success: update_dom
};
function update_dom(data) {
$('#picworks').html('<img src="' + data.path + '" alt="Illustration" />');
}
$('#uploadForm').submit(function(){
$(this).ajaxSubmit(submit_options);
return false;
});
});

Categories