I build SPA on Django and I want to GET and POST JSON data based on request.user.
Something like this:
def get(self, *args, **kwargs):
return {
"data": [
i.get_json() for i in Customer.objects.filter(pk=self.request.user.pk)]
}
But I confuse, how it possible to put my user in request by REST service, like "Postman" or "Curl".
Postman has "Authorization" field, so I put login and password into it and my headers update with:
Authorization Basic YWdlbmN5X3NwYUBtYWlsLnJ1OjExMTEx
And I test it with curl:
curl -u myuser:11111 http://127.0.0.1:8000/api/myurl/
But user still - AnonymousUser
It could work with angular later, but I don't understand how I can test it now.
I found solution. I need to login with my user first and take sessionid from Cookie, then put sessionid in request.
Postman has nice extension named "Postman Interceptor", it put all session from browser into request authomaticly.
Related
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.
Here my API:
#login_required
#api_view(['GET'])
def get_order(request):
order_list = Order.objects.values("user_name",
"user_surname",
"order_date").all()
return HttpResponse(json.dumps([x for x in order_list])
The problem is when i add #login_required, i'm trying to do a Postman GET request using BASIC authentication with username and password.
If i remove the #login_required, i can perform a succesful GET request without auth in Postman.
First, login with your browser. Next, locate where the corresponding authentication cookie is stored in your browser. Copy it to your clipboard. Finally, paste the cookie and pass it along with the GET request in Postman:
The name of the cookie is sessionid.
I'm having very weird issue with session authentication.
I'm using session authentication over DRF APIs for some legacy django views. And login process implemented with DRF and react app.
The server code for sign-in looks like this:
class AuthViewSet(viewsets.ViewSet):
def create(self, request, *args, **kwargs):
is_session_auth = request.data.get('session_auth', False)
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
token = serializer.save()
if is_session_auth is True:
login(request, token.user)
return Response(dict(token=token.key))
So, as far as I expected, the response should has set-cookie header which makes browser to set sessionid and csrftoken cookies. And it works well most of times.
But rarely, some users experiencing login failures. I'm faild to reproduce it, but this is what they describe:
When user submit sign in form, the request sent to the server and got response successfully.
Then the javascript app push url to login/complete, as expected.
But in login complete view, the request failed to authenticate. And the view redirect request to the original login view.
User retry login, but got same result.
I have no idea how this happened so rarely, to the so small amount of users. Am I miss something?
Thanks for help.
==============
Add some more information.
I dig into this problem, and find out that users' sessions are not decodable.
session.get_decoded() for session in Session.objects.all() returns Session data corrupted error. Is it relevant to login failure?
I'm not sure I'm right on track. Please give me a hint or direction.
I set up my Web service using Django and also made mobile app with React Native using Django REST framwork. Django uses the basic session authentication, but Django REST API uses token authentication to process the request from mobile app.
I want to implement small ReactJS app into my existing Django web. At this stage, I think my small react app will need auth token to communicate with REST api for itself.
So, my idea is that when user logs in web login page, user's API token needs to be received from API and save into cookie or localStorage while normal log in process is processing in Django Web service. Because I don't want to let users log in again to run react app on my web page to get auth token.
Am I right on track? if so, how can I make it works? Please refer to my code in Django login view.py Do i need to some code in order to get API auth token and save it into client side?
def Login(request):
if not request.user.is_authenticated:
if request.method == "POST":
email = request.POST['email']
password = request.POST['password']
user = authenticate(email = email, password = password)
if user is not None:
login(request, user)
messages.add_message(request, messages.SUCCESS, request.user.nickname + ' Welcome!')
return redirect('Search')
else:
messages.add_message(request, messages.WARNING, 'Please check Email / Password again')
return redirect('login')
else:
form = LoginForm()
return render(request, 'login.html', {'form': form })
else:
return redirect('main')
You have done some useless in your login function. you can use jwt. it has some good function for supporting login. In its login function, when send username and password with post, it return token to client.
http://getblimp.github.io/django-rest-framework-jwt/
You just need set urlpattern
from rest_framework_jwt.views import obtain_jwt_token
#...
urlpatterns = [
'',
# ...
url(r'^api-token-auth/', obtain_jwt_token),
]
It return token
$ curl -X POST -d "username=admin&password=password123" http://localhost:8000/api-token-auth/
In other request, if you need authentication, use following request
$ curl -H "Authorization: JWT <your_token>" http://localhost:8000/protected-url/
They both carrying out similar tasks with few differences.
Token
DRF's builtin Token Authentication
One Token for all sessions
No time stamp on the token
DRF JWT Token Authentication
One Token per session
Expiry timestamp on each token
Database access
DRF's builtin Token Authentication
Database access to fetch the user associated with the token
Verify user's status
Authenticate the user
DRF JWT Token Authentication
Decode token (get payload)
Verify token timestamp (expiry)
Database access to fetch user associated with the id in the payload
Verify user's status
Authenticate the user
Pros
DRF's builtin Token Authentication
Allows forced-logout by replacing the token in the database (ex: password change)
DRF JWT Token Authentication
Token with an expiration time
No database hit unless the token is valid
Cons
DRF's builtin Token Authentication
Database hit on all requests
Single token for all sessions
DRF JWT Token Authentication
Unable to recall the token without tracking it in the database
Once the token is issued, anyone with the token can make requests
Specs are open to interpretations, no consensus on how to do refresh
Reference: Django : DRF Token based Authentication VS JSON Web Token
I'd like to leave my answer after I solved in my way through my long research and study. My solution is quite simple.1. set DRF session authentication enable. Adding some code in setting.py
REST_FRAMEWORK = {
# ...
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
}
2. add 'credentials: "include"' into fetch code to use already logged in session cookie for authentication.
await fetch(API_URL, {
credentials: "include"
})
this solution solved my case.
I've constructed a APIView as such:
class CustomAPIView(APIView):
def get(self, request, *args, **kwargs):
if not request.user or not request.user.is_authenticated():
return Response("User not logged in", status=status.HTTP_403_FORBIDDEN)
# Other stuff
And in my html template I'm making a call to it using fetchAPI:
fetch('/api/request/url/', {method: 'get'})
.then(
// Process info );
I'm logged in through all this, but I'm always being greeted with a 403 response with the request.user variable in the APIView returning AnonymousUser. However, if I try and visit the api url manually everything works out right.
Can someone point out what I'm missing?
Thanks in advance.
The issue with fetch api is that by defualt it will not send cookies to the server.
By default, fetch won't send or receive any cookies from the server,
resulting in unauthenticated requests if the site relies on
maintaining a user session (to send cookies, the credentials init
option must be set).
So You have to set credentials: 'same-origin' in your fetch request,
fetch('/api/request/url/', {method: "GET", credentials: 'same-origin'})
.then(
// Process info );
for cross-origin requests, use credentials: 'include'