Cookies not working with an AJAX call from jQuery to Django - django

I have a Django site using a 5-star rating system for voting (I use django-ratings) and I would like to store the votings of the users with AJAX calls.
On the client side I have a JavaScript function sending a GET request to a URL:
$.ajax({
url: url,
success: function(data) {
alert('Load was performed.');
}
});
On the server side I have code setting the cookie:
def vote(request, slug, rating):
# Some irrelevant code...
response = HttpResponse('Vote changed.')
response.set_cookie('vote', 123456)
return response
The problem is that the cookie is never set in the browser.
What I am doing wrong?
Thanks!

Are sure that your problem is about Cross-site request forgery protection? most ajax requests rejected django by that. Don't you have any error messages?

Related

Jsonresponse in Django working in browser but not in PostMan or Angular

I am trying to send a JSON response from Django back-end to my angular front-end.
When I make the request I receive nothing in Postman or Angular but,opening the link in browser seems to be returning the correct result
My View is :
#api_view(['GET'])
def my_view(request):
print(request.user.username)
return JsonResponse({'username': request.user.username})
When I open http://127.0.0.1:8000/accounts/get_username/ in browser I receive
{"username": "aditya8010"} on the web page.
But when i do a get request using POSTMAN I recieve
{
"username": ""
}
Same with Angular
this.http.get("http://127.0.0.1:8000/accounts/get_username/").subscribe((res) => {
this.username = JSON.stringify(res["username"])
console.log(this.username," ", res)
})
this code also prints an empty username string.
Another thing I have noticed is that my print statement in the view does print anything random I put in there when called from POSTMAN or Browser but when I use request.user.username it doesnt print anything when called by POSTMAN.
And each time the response code is 200
What am I doing wrong.
When you're sending the request you are not providing authentication credentials (i.e. something that identifies the user that is sending the request). How do you obtain this credentials?
You need to establish an authentication method. There are several but I recommend using Token authentication with knox package. Basically, you have an endpoint that logins the user with his username and password (normal json post request) and that endpoint returns a token. This token is what identifies the user. You send this token in the header of each request you need to be authenticated. That means you probably should include an IsAuthenticated permission for the view. In postman:
API view:
from rest_framework.permissions import IsAuthenticated
#api_view(['GET'])
#authentication_classes([IsAuthenticated])
def my_view(request):
print(request.user.username)
return JsonResponse({'username': request.user.username})
When it is in a browser, your login information is remembered in the session. When using postman or Angular, you need to provide the user's information in the request header manually.

Redirect From REST_API Response

I am using Angular and Django in my stack for a website, and after a user registers it emails them a link to activate their account. As of right now everything is working but the link takes the user to the Django rest framework page.
I've been returning responses in my app like this
data = {'success': True, 'message': 'An account has been activated.', 'response': {}}
return Response(data, status=status.HTTP_201_CREATED)
I am curious on how to redirect a user back to the login page which at the current moment would be a localhost page such as http://localhost:4200/#/authentication/login.
From research I have found methods like
return redirect('http://localhost:4200/#/authentication/login')
but I am wanting to keep my responses consistent. Is there a way to redirect a user while still using the rest api Response object?
After thinking about the comment posted by Muhammad Hassan, I realized I was thinking about this all wrong. Instead of sending a Django url I have change the email to send a URL to an Angular page I made and then I just sent an HTTP request from that page to the Django URL.

Connect users to a Django website with React-Native

I have a Django website running, where users can login, save data, take notes, etc. I want to make a mobile app for this website and I am looking into react-native, as I made my website front end with React-JS.
I want to be able to fetch users data on the website from the app. I saw that React-Native had the fetch function, similar to AJAX calls. The problem is that I need the user to be authenticated for the POST call to return something, as I am reading the request.user value to grab the proper data. I also know that without the proper csrf token, Django won't allow a POST call.
How can I do a fetch with the proper request.user value and pass the csrf security test from the react-native app?
For your mobile application, I would create first of all and API with Django Rest Framework. In authentication, you should use Token Authentication so in each request will have the follow hearder Authorization: Token user_token. With this token you can identidy the user as usual using request.user in your views.
In React-Native, you should use axios to do the request for login( to get the token) and them the user data:
const config = {
headers: {
'X-CSRFToken': Cookies.get('csrftoken'),
'Content-Type': 'application/json'
}
};
axios.get(`${ROOT_URL}api/users/data/`, config_user)
.then(response => {
console.log(response.data) // User Data
});

django and angular.js with authentication

I have a web app that's already written in Django, and it is working quite well. I want to add a few views for angular as the plan is to move into that direction. One issue i'm facing is that some of my controllers require login, with django we normally use the #login_required decorator and everything is fine.
But with angular.js calling the controllers (for api's), the redirect is not happening. I'm assuming I'll have to somehow check if my django user is authenticated directly from angular side. Is there any explanation on how to confirm this on angular? I have been struggling with this and have read the following:
https://docs.angularjs.org/api/ng/service/$http
https://medium.com/#vince_prignano/angular-js-with-django-bde834dbd61e
$routeProvider not triggered after login redirect
http://www.django-rest-framework.org/api-guide/authentication/
Basically, I want to confirm, via Angular, that my user is logged in and if not, redirect them to the login page.
EDIT
I'm implementing a request interceptor as shown here:
Interceptor not working
However, in django #login_required it's returning the html of the redirecting page. Is there a way to get the URL and forward the user there?
Add resolve in your $routeProvider as:
$routeProvider
.when('/', {
templateUrl: '/views/main.html' })
.when('/admin', {
templateUrl: 'views/admin.html',
controller: 'AdminCtrl',
resolve: { loggedin: checkLoggedin } })
.when('/login', {
templateUrl: 'views/login.html',
controller: 'LoginCtrl' })
.otherwise({ redirectTo: '/' }); -
See more at: https://vickev.com/#!/article/authentication-in-single-page-applications-node-js-passportjs-angularjs
As mentioned in the previous answer, it would be best if your Django back-end can issue a 401 response when login is required. Right now it sounds like it's sending a 302, which you can still observe in the browser if you're making an XHR request. As you've found, using $http interceptors in Angular are a common way of looking for a 401 and sending the user to a login page.
I've taken a different approach: implement a service that abstracts this a bit, via a method called $user.get() - it makes a request to a known endpoint (in my case, /api/users/current) and rejects the returned promise if it sees a 401. In your case you could implement a rejection handler that uses window.location.href to send the user to your dedicated login page
Disclaimer: I work at Stormpath and we’ve spent a log of time thinking about this :) In my comments above I’m referring to our Stormpath Angular SDK - you can look at this library to see how I’ve solved this problem.
When defining my app i'm doing this:
$httpProvider.interceptors.push('errorInterceptor');
and The code for that is below:
app.factory('errorInterceptor', ['$q', '$rootScope', '$location',
function ($q, $rootScope, $location) {
return {
request: function (config) {
return config || $q.when(config);
},
requestError: function(request){
return $q.reject(request);
},
response: function (response) {
return response || $q.when(response);
},
responseError: function (response) {
if (response && response.status == 302 && response.data.url) {
window.location = response.data.url;
return;
}
return $q.reject(response);
}
};
}]);
Basically, we can't use login_required. We have to create a new decorator and provide a 302 status with a url.
If you're making APIs calls via AJAX back to the server, most likely you don't want the response to be redirected to the login page.
I have the same use case and made my own decorator to return a 403 when the user is not logged in. You may also use 401 instead if you like (I left it commented out).
I use 403 because 401 seems to imply WWW authentication.
from django.http import HttpResponse, HttpResponseForbidden
def logged_in_or_deny(func):
def check_request(request, *args, **kwargs):
if (request.user.is_authenticated()):
return func(request, *args, **kwargs)
else:
return HttpResponseForbidden('You must be logged in') # 403 Response
#return HttpResponse('You must be logged in', status=401) # 401 Response
return check_request
Then you would protect your view like this:
#logged_in_or_deny
def your_view(request):
# ... your code ...
return HttpResponse('Your normal response :)')
From Angular, it seems like you already know how to use an interceptor to check the response code and redirect the user accordingly. If you use the 403 or 401, you should check the against the response body just in case you respond with similar errors in the future.
While what you already have would work, 302 responses can be used for other reasons. It's better to have an explicit 4xx response rather than a 3xx redirection response since it'll be immediately obvious that it's a client side error (missing authentication).
You can use Http-Auth-Interceptor. Suppose A view requires login and a user makes a request to the view without login then #login_required decorator returns the response with response code 401. In auth interceptor intercept the status code if status code is 401 then redirect user to the login page.
example site: http://witoldsz.github.io/angular-http-auth/

Django API for login/logout with S3 site is not creating cookies

I'm working with a static webpage hosted on S3 and I'm using a Django as my api for session management.
I have my JS code on S3 POSTing to django when users sign in to my web site but I'm not getting any cookies saved on my browser.
I'm not sure if it's the jQuery $.post that is not accepting cookies or if it's Django that's not allowing the sending of cookies. How would I overcome this?
I currently also have a url endpoint on my django app where I can check if cookies are working but when I hit the url I get the standard message
Please enable cookies and try again.
Although my browser accepts cookies.
I get these urls to work fine when I use a Django rendered page to interact with them.
Any help would be greatly appreciated - thanks
Edit - showing code:
I use Janrain to allow user to login via facebook, twitter, etc..
how Janrain works
user clicks sign in button, uses facebook/wtv to login
Janrain get's user data on their servers and gives you a token which I post to django via this function
janrain.events.onProviderLoginToken.addHandler(function(tokenResponse) {
$.ajax({
type: "POST",
url: post_form_url,
data: formdata + "&token=" + tokenResponse.token,
success: function(res, textStatus, jqXHR) {
//do stuff now that we are logged in ...
console.log(jqXHR.getResponseHeader('Set-Cookie')); //returns null
//$('#redirect').submit();
},
});
In Django
def login_via_janrain(request):
if request.method == "POST":
janrain_token = request.POST.get('token')
// communicate w/janrain api to get info from this token (i.e. who just logged in via this token)
#create (or pull) user based on data returned from janrain api and do a Django login
auth.login(request, user)
#return success msg to $.post (session cookies should be automatically included in the response)
return HttpResponse("success")
Using S3
I currently have a static site hosted on S3. I tested these urls using django rendered views but ultimately I want the S3 site to render the views and just use django as an api endpoint.
I can currently login from the S3 site but after a successful login I have no cookies to show for it... I think django isn't sending back cookies...