Connect users to a Django website with React-Native - django

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

Related

How to implement admin login and logout using Django REST framework?

I have been given a task to authenticate admin login programmatically and logout as well.
I am able to to do login but on logged out when I check which user I am logging out it says AnonymousUser. How can I make sure I log out current user which is logged it.
I am using Django REST framework and testing it on Postman.
#api_view(["POST"])
def adminLogin(request):
if(request.method=="POST"):
username = request.data["username"]
password = request.data["password"]
authenticated_user = authenticate(request,username=username, password=password)
if authenticated_user != None:
if(authenticated_user.is_authenticated and authenticated_user.is_superuser):
login(request,authenticated_user)
return JsonResponse({"Message":"User is Authenticated. "})
else:
return JsonResponse({"message":"User is not authenticated. "})
else:
return JsonResponse({"Message":"Either User is not registered or password does not match"})
#api_view(["POST"])
def adminLogout(request):
print(request.user)
logout(request)
return JsonResponse({"message":"LoggedOut"})
Logging in/logging out with a REST API makes not much sense. The idea of logging in/logging out, at least how Django implements it, is by means of the session, so with a cookie that has the session id.
API clients like Postman usually do not work with cookies: each request is made more or less independent of the previous one. If you thus make the next request without a reference to the session, then the view will not link a user to that request. Clients like AJAX that runs on the browser of course can work with cookies, since these are embedded in the browser that manages cookies. You can work with cookies in postman as specified in this tutorial [learning postman], but this is usually not how an API is supposed to work.
This is why APIs usually work with a token, for example a JWT token. When authenticating, these are given a token that might be valid for a short amount of time, and subsequently it uses that token to make any other request that should be authorized.
As the Django REST framework documentation on TokenAuthentication [drf-doc] says, you can define views that create, and revoke tokens. The page also discusses session authentication that thus can be used for AJAX requests.
But likely you are thus using the wrong means to do proper authentication for your REST API, and you thus might want to work with a token like a JWT token instead.

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.

How can I transfer Django session authentication to my Vue frontend?

My app uses Django and rest framework backend, Vue frontend. I would like users to use session authentication and login via Django's allauth, with its email verification and password reset support. On login, users are redirected to a Vue component, and I can put the CSRF token into request headers.
I need to get user object (or user ID) into my Vuex store at this point. Are these my choices, or are there others?
give up using session authentication and use JWT
put some kind of session data or token into localstorage that Vue could then retrieve. (How could I do this?)
somehow get user ID from CSRF token
Any advice appreciated.
Duh. Sending request to view/endpoint for getting the authenticated user using Django's request.user worked like a charm, given that my Vue is also running on same localhost:8000 port as Django
in views.py:
class AuthUserView(APIView):
def get(self, request):
serializer = AuthUserSerializer(request.user)
return Response(serializer.data)
in Vue:
methods: {
getUser() {
fetch('/api/auth_user')
.then(response => response.json())
.then(data => console.log(data));
}
}

Generating CSRF token for Backbone from Django

I've been developing a backbone layer on top of Django and using Django to create the API and having backbone models calling django api to fill in the models. I'm trying to create a login for users using the default django models for users. Since I'm not rendering the pages through django but instead through router in backbone. I can't generate csrf token through django's template language {{ csrf_token }} and thus I can't post any forms.
One way I thought to work around this is to generate the token by having the backbone view fetch from the api endpoint in initialize and have the endpoint generate the token through
token = csrf._get_new_csrf_key()
and then passing it to backbone frontend through json then following the django documentation
var csrftoken = "<%=obj.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);
}
}
});
This didn't work since I still get Forbidden (403) CSRF verification failed. Request aborted.
Any help would be appreciated. Thanks
The simplest workaround is to read the csrftoken cookie and pass it to django via as X-CSRFToken header. This section in the Django docs should give you the correct example:

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...