I am trying to apply Facebook Login API in django project. I planned to use Facebook username and default password(as far as django doesn't allow to create users without pass) and authenticate via ajax.
FB.api('/me', function(response) {
alert(response.name); // it's fine, it's there
ajaxPost('/authfb/', {'username': response.name}, function(){ });
});
What I get in log is :
Failed to load resource: the server responded with a status of 403 (FORBIDDEN)
And in alert message:
POST /authfb/ 403 FORBIDDEN
undefined
I am using django-ajax with decorator, but it works for me in all other parts of code.
views.py:
#ajax
def authfb(request):
if request.method == "POST":
username = request.POST.get('username')
password = '112358'
user = auth.authenticate(username=username, password=password)
if user is not None:
auth.login(request, user)
username = auth.get_user(request).username
print ('logged in succesfully')
return redirect("/user/%s/" % username)
else:
print("The username and password were incorrect.")
error_message_login_page = 'you do not exist'
return render(request, 'blog/facebook.html', {'error_message_login_page':error_message_login_page})
else:
print("whatever")
In similar questions csrf security is often pointed as issue. So I tried this js code, which might be right, but still didn't help:
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');
$.ajaxSetup({
headers: { "X-CSRFToken": getCookie("csrftoken") }
});
EDIT:
def fblogin(request):
if request.user.is_authenticated():
username = auth.get_user(request).username
return redirect("/user/%s/" % username)
print(username)
else:
return render(request, 'blog/facebook.html', {})`
Try this instead of yours.
function getCookie(name) {
var value = "; " + document.cookie;
var parts = value.split("; " + name + "=");
if (parts.length == 2) return parts.pop().split(";").shift();
}
Also
ajaxPost('/authfb/', {'username': response.name, 'csrfmiddlewaretoken': getCookie('csrftoken')}, function(){ });
Update
Add
{% csrf_token %}
somewhere inside body of facebook.html
Related
I need to make a hyperlink in Django for a POST-request. For example, "Add to blacklist" in the menu. It's easy to do with a form with a submit button but I need a menu item not button. I found Javascript code for doing this but it gives me an error 403: CSRF token missing or incorrect. And I couldn't find understable for me information how to insert csrf-token into the Javascript function. I don't know Javascript, I write in Python.
Here's the function from https://ru.stackoverflow.com/questions/65237/Вызов-метода-post-через-ссылку:
<script type="text/javascript">
function postToUrl(path, params, method) {
method = method || "post";
var form = document.createElement("form");
form.setAttribute("method", method);
form.setAttribute("action", path);
for(var key in params) {
var hiddenField = document.createElement("input");
hiddenField.setAttribute("type", "hidden");
hiddenField.setAttribute("name", key);
hiddenField.setAttribute("value", params[key]);
form.appendChild(hiddenField);
}
document.body.appendChild(form);
form.submit();
}
</script>
Here's how I call it:
To blacklist
This is my view:
class AddToBlacklistView(View):
def post(self, request, watched_user_id, next_url=None, *args, **kwargs):
if not next_url:
next_url = '../profile.html/user_id{0}'.format(watched_user_id)
if request.user.is_authenticated:
try:
user = User.objects.select_related("profile").get(username=request.user)
watched_user = User.objects.select_related("profile").get(id=watched_user_id)
except User.DoesNotExist:
raise Http404
if watched_user.id == user.id:
return redirect(next_url)
if watched_user not in user.profile.blacklist.all():
user.profile.blacklist.add(watched_user)
user.save()
if watched_user.profile in user.profile.friends.all():
user.profile.friends.remove(watched_user.profile)
if user.profile in watched_user.profile.friends.all():
friendship = Friendship.objects.get(user=watched_user.profile, friend=user.profile)
if friendship.status != 3:
friendship.status = 2
friendship.save()
if watched_user in user.profile.bookmarks.all():
user.profile.bookmarks.remove(watched_user)
return redirect(next_url)
else:
return redirect(next_url)
I tried this and it didn't help:
<meta name="csrf-token" content="{{ csrf_token }}">
<script>
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
</script>
I also tried to pass as params this and it didn't help:
csrfmiddlewaretoken: '{{ csrf_token }}'
Upd:
I also tried to add the decorator for a view and it continued to throw the same error:
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_protect
#method_decorator(csrf_protect)
def post ...
I also tried # method_decorator(ensure_csrf_cookie) on the view that renders the page with HTML that calls the Javascript function and I still get 403 error.
I also tried this code from https://docs.djangoproject.com/en/3.0/ref/csrf/ and it continued to throw the same 403 error.
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// 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;
}
const csrftoken = getCookie('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);
}
}
});
Please help me!
I found a solution here:
submitting a hyperlink by GET or POST
I had to modify it because on my page there is a list of people with a menu for each one of them in such a way:
<form id="myform1_{{ message.recipient.user.id }}" method="post" action="/account/add_to_blacklist/watched_user_id{{ message.recipient.user.id }}/next={{ request.get_full_path }}" >
{% csrf_token %}
</form>
Add to blacklist
I'm trying to send ajax post requests to my server to add or remove objects by using just checkboxes (not form). Here is a screenshot of what I got visually:
https://pasteboard.co/IMHHSa6.png
When I click any of the checkboxes I got http500 (internal server error) as response. In cmd I see the error that says there is no matching query: app1.models.Influencer.DoesNotExist: Influencer matching query does not exist.
The thing is I'm pretty sure that the object with that id exists in the database. I spend much time inspecting Django's CSRF documentation and watching youtube videos about django-ajax examples. Here is my code:
views.py:
class InfluencerListView(LoginRequiredMixin, ListView):
model = Influencer
context_object_name = 'influencers' # not necessary, default is object_list
def post(self, request, *args, **kwargs):
inf_id = request.POST.get('inf.id')
list_id = request.POST.get('list.id')
i = Influencer.objects.get(id=inf_id)
l = InfluencerList.objects.get(id=list_id)
l.influencers.add(i)
data = {
'result' : 'some result'
}
return JsonResponse(data)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
logged_in_user = self.request.user
context['myLists'] = logged_in_user.lists.annotate(influencers_count=Count('influencers'))
return context
models.py:
class Influencer(models.Model):
# fields are not included for the sake of clarity
class InfluencerList(models.Model):
name = models.CharField('Name:', max_length=20, blank=False)
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='lists')
influencers = models.ManyToManyField('Influencer', related_name='lists')
scripts.js
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 = cookies[i].trim();
// 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;
}
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function myFunc(_self) {
inf_id = _self.getAttribute('data-inf_id');
list_id = _self.getAttribute('data-list_id');
console.log(inf_id + " " + list_id); # I CAN SEE THOSE IDS IN CONSOLE AND THEY EXIST IN DB
var csrftoken = getCookie('csrftoken');
if(_self.checked == true){
console.log("checked!");
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
$.ajax({
method: 'POST',
url: '/influencers',
data: {
'inf_id': inf_id,
'list_id': list_id,
'csrfmiddlewaretoken': csrftoken
},
dataType: 'json',
success: function (data) {
console.log("succes!");
}
});
}
else{
console.log("unchecked!");
}
}
I also added this line somewhere in my view file (where I put it doesn't matter as long as it's in the body since I'm not using any forms. Please correct me if I'm wrong):
<input type='hidden' name='csrfmiddlewaretoken' value='{{ csrf_token }}' />
I'm creating an event registration page.
On this page, users need to be able to search for a database item so it can be registered to this event. Therefore, the POST request must be submitted to a different URL than what the user is on, so that it doesn't interfere with the form wizard sequence.
This is my javascript:
(document).ready(function() {
$('#primary_artist_lookup').on('input', function(){
console.log("Listener success");
var searchItem = $('#primary_artist_lookup').val();
$.ajax({
url : $('#lookupLink').val(),
type : "POST", //http method
data : searchItem,
dataType: "json",
// handle a successful response
success : function (json) {
console.log(json); // log the returned json to the console
console.log("success"); // another sanity check
},
// handle a non-successful response
error : function(xhr,errmsg,err) {
$('#results').html("<div class='alert-box alert radius' data-alert>Oops! We have encountered an error: "+errmsg+
" <a href='#' class='close'>×</a></div>"); // add the error to the dom
console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
}
});
});
The url is a hidden html value that maps to the url I am trying to POST the data to:
<p hidden id="lookupLink">{% url "Users:lookup" %}</p>
There is an additional js portion to submit a CSRF token to Django for security purposes:
// CSRF VALIDATION //
// This function gets cookie with a given name
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');
/*
The functions below will create a header with csrftoken
*/
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function sameOrigin(url) {
// test that a given url is a same-origin 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 isn't scheme relative or absolute i.e relative.
!(/^(\/\/|http:|https:).*/.test(url));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
// Send the token to same-origin, relative URLs only.
// Send the token only if the method warrants CSRF protection
// Using the CSRFToken value acquired earlier
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
return false;
});
When I try to use this ajax function, it doesn't post to the url I request, but rather the page that the users are on. What am I doing wrong?
use text() instead:
url : $('#lookupLink').text(),
and data should be an object:
data : { searchItem : searchItem },
In Django Template Without using form i want to upload files to my web server. so for that i`m using javascript library called dropzonejs.
I exactly follow this tutorial bootstrap dropzonejs. I setup everything to run the demo.
You see i decided not to use form so obviously the problem csrf_token is missing when upload happens time.
My doubt is how to include csrf_token in javascript. ?
This is the information they added in their home page for how to add csrf token
sending - Called just before each file is sent. Gets the xhr object and the formData objects as second and third parameters, so you can modify them (for example to add a CSRF token) or add additional data.
Are you understand my question ? give me some idea to do that ?
You could either have the view CSRF exempt:
from django.views.decorators.csrf import csrf_exempt
class YourView(models.View):
#csrf_exempt
def dispatch(self, *args, **kwargs):
return super(YourView, self).dispatch(*args, **kwargs)
The JavaScript config would probably look something similar to this:
(function($){
$(function(){
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');
function csrfSafeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
crossDomain: false,
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type)) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
});
})(jQuery);
Here's what I am looking for.
I have an UpdateView, which renders the form from CreateView with fields loaded from database. Instead my edit form has readonly html attribue. So what I need is to drop readonly on click on the form field and when i enter new value it will be automaticaly updated when cursos moves to the next field.
How do i handle POST actions with out submit button?
you can use JavaScript(Jquery) to do so, blur event
EDITED: about CSRF verification,see https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax
about $.post see:https://api.jquery.com/jQuery.post/
template.html
<script type="text/javascript" src="/media/js/jquery-1.10.2.min.js"></script>
<script>
// using jQuery
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;
}
$(document).ready(function(){
$("#myinput").blur(function(){
var csrftoken = getCookie('csrftoken');
$.ajaxSetup({
beforeSend: function(xhr) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
});
$.post('/link-to-fun/',{"value":value});
});
});
</script>
<input type="text" id="myinput">
url.py
write a special url(/link-to-fun/) to function in views.py
url(r'^link-to-fun$', views.change_db_value),
views.py
def change_db_value(request):
value = request.POST.get('value','')
# database operation