Using Requests python library to connect Django app failed on authentication

11,301

Solution 1

In Django authentication works in following way:

  • There is a SessionMiddleware and AuthenticationMiddleware. The process_request() of both these classes is called before any view is called.
  • SessionMiddleware uses cookies at a lower level. It checks for a cookie named sessionid and try to associate this cookie with a user.
  • AuthenticationMiddleware checks if this cookie is associated with an user then sets request.user as that corresponding user. If the cookie sessionid is not found or can't be associated with any user, then request.user is set to an instance of AnonymousUser().
  • Since Http is a stateless protocol, django maintains session for a particular user using these two middlewares and using cookies at a lower level.

Coming to the code, so that requests can work with django.

You must first call the view where you authenticate and login the user. The response from this view will contain sessionid in cookies.

You should use this cookie and send it in the next request so that django can authenticate this particular user and so that your request.user.is_authenticated() passes.

from django.contrib.auth import authenticate, login

def login_user(request):
    user = authenticate(username=request.POST.get('username'),  password=request.POST.get('password'))
    if user:
       login(request, user)
       return HttpResponse("Logged In")
    return HttpResponse("Not Logged In")

def getAllTracks(request):
    if request.user.is_authenticated():
        return HttpResponse("Authenticated user")
    return HttpResponse("Non Authenticated user")

Making the requests:

import requests

resp = requests.post('http://127.0.0.1:8000/login/', {'username': 'akshar', 'password': 'abc'})

print resp.status_code
200 #output

print resp.content
'Logged In' #output

cookies = dict(sessionid=resp.cookies.get('sessionid'))

print cookies
{'sessionid': '1fe38ea7b22b4d4f8d1b391e1ea816c0'}  #output

response_two = requests.get('http://127.0.0.1:8000/getAllTracks/', cookies=cookies)

Notice that we pass cookies using cookies keyword argument

print response_two.status_code
200  #output 

print response_two.content
'Authenticated user'  #output

So, our request.user.is_authenticated() worked properly.

response_three = requests.get('http://127.0.0.1:8000/hogwarts/getAllTracks/')

Notice we do not pass the cookies here.

print response_three.content
'Non Authenticated user' #output

Solution 2

I guess, auth keyword for Requests enables HTTP Basic authentication which is not what is used in Django. You should make a POST request to login url of your project with username and password provided in POST data, after that your Requests instance will receive a session cookie with saved authentication data and will be able to do successful requests to auth-protected views.

Solution 3

Might be easier for you to just set a cookie on initial authentication, pass that back to the client, and then for future requests expect the client to send back that token in the headers, like so:

r = requests.post('http://127.0.0.1:8000', auth=(UN, PW))
self.token = r.cookies['token']
self.headers = {'token': token}

and then in further calls you could, assuming you're in the same class, just do:

r = requests.post('http://127.0.0.1:8000/getAllTracks', headers=self.headers)
Share:
11,301
handsomegui
Author by

handsomegui

Python Newbie here. Keep learning!

Updated on June 28, 2022

Comments

  • handsomegui
    handsomegui almost 2 years

    Maybe a stupid question here: Is Requests(A python HTTP lib) support Django 1.4 ?

    I use Requests follow the Official Quick Start like below:

    requests.get('http://127.0.0.1:8000/getAllTracks', auth=('myUser', 'myPass'))
    

    but i never get authentication right.(Of course i've checked the url, username, password again and again.)

    The above url 'http://127.0.0.1:8000/getAllTracks' matches an url pattern of the url.py of a Django project, and that url pattern's callback is the 'getAllTracks' view of a Django app.

    If i comment out the authentication code of the 'getAllTracks' view, then the above code works OK, but if i add those authentication code back for the view, then the above code never get authenticated right.

    The authentication code of the view is actually very simple, exactly like below (The second line):

    def getAllTracks(request):
        if request.user.is_authenticated():
            tracks = Tracks.objects.all()
            if tracks:
                # Do sth. here
    

    Which means if i delete the above second line(with some indents adjustments of course), then the requests.get() operation do the right thing for me, but if not(keep the second line), then it never get it right.

    Any help would be appreciated.

  • Ranjeet
    Ranjeet over 8 years
    Will you not get a csrftoken error, I am getting that when i try to login the way you have suggested.
  • MD. Khairul Basar
    MD. Khairul Basar almost 7 years
    @akshar How can I login to website using requests from django view ? I tried it the way you showed but it doesn't stay logged in.