I'm developing a desktop application where users can log in using credentials from my Django website's database. The goal is for users to be able to create posts on the Django website (forum) through the desktop application.
In the desktop app's code, I have the following code, which successfully retrieves a CSRF token from Django:
def get_csrf_token():
# Make a GET request to your Django server to fetch the CSRF token
response = requests.get('http://127.0.0.1:8000/accounts/get-csrf-token/')
# Check if the request was successful (status code 200)
if response.status_code == 200:
# Extract the CSRF token from the response JSON
csrf_token = response.json().get('csrf_token')
print("CSRF TOKEN: ", csrf_token)
return csrf_token
else:
# Handle errors, such as failed requests
print(f"Failed to fetch CSRF token. Status code: {response.status_code}")
return None
And the following code which should send the data (username, password, CSRF token) to Django:
def login(self):
# Retrieve username and password from input fields
username = self.username_input.text()
password = self.password_input.text()
# Send login request to Django server
url = "http://127.0.0.1:8000/accounts/login/"
data = {
"username": username,
"password": password,
}
# Define the headers with the CSRF token
headers = {
'X-CSRFToken': get_csrf_token()
}
print("x-csrftoken: ", headers['X-CSRFToken'])
response = requests.post(url, data=data, headers=headers)
if response.status_code == 200:
# Authentication successful
self.accept()
else:
# Authentication failed
QMessageBox.warning(self, "Login Failed", "Invalid username or password")
The code above is sending a request to http://127.0.0.1:8000/accounts/login/
, which is linked to CustomLoginView in my urls.py:
path('login/', CustomLoginView.as_view(template_name='accounts/login.html'), name='login')
And this the code in my views.py:
class CustomAuthenticationForm(AuthenticationForm):
def clean_username(self):
print("Entering clean_username method.......")
username = self.cleaned_data.get('username')
if username:
# Perform a case-insensitive lookup for the username
return CustomUser.objects.filter(username__iexact=username).first()
return None
class CSRFTokenView(APIView):
authentication_classes = [SessionAuthentication]
def get(self, request, format=None):
print("Entering get method......")
csrf_token = get_token(request)
print("csrf token inside get method of CSRFTokenView: ", csrf_token)
return Response({'csrf_token': csrf_token})
class CustomLoginView(LoginView):
authentication_form = CustomAuthenticationForm
def get_success_url(self):
print("Entering get_success_url method......")
return reverse_lazy('thread_list')
And when I try to login via the desktop app, I get the following message from Django:
Forbidden (CSRF cookie not set.): /accounts/login/
"POST /accounts/login/ HTTP/1.1" 403 2869
And I'm not getting print statements from CustomAuthenticationForm and CustomLoginView.
This is in my settings.py:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
I've tried commenting out 'django.middleware.csrf.CsrfViewMiddleware',
from settings.py.
I've tried adding csrf_exempt decorator to CustomLoginView:
@method_decorator(csrf_exempt, name='dispatch')
class CustomLoginView(LoginView):
def post(self, request, *args, **kwargs):
if request.method == 'POST':
print("Received POST data:", request.POST)
print("Received headers:", request.headers)
return super().post(request, *args, **kwargs)
authentication_form = CustomAuthenticationForm
def get_success_url(self):
print("get_success_url method......")
return reverse_lazy('thread_list')
I've tried adding csrf_exempt to urls.py path.
I've even tried removing {% csrf_token %}
from the login form. But I keep getting the same message.
Solved it.
I've logged in via the website and the CustomLoginView returned the print statements:
print("Received POST data:", request.POST)
print("Received headers:", request.headers)
Found out that the CSRF token was sent both in the data, as well as the headers.
So I changed the code on the desktop app to this:
url = "http://127.0.0.1:8000/accounts/login/"
csrf_token = get_csrf_token()
data = {
"csrfmiddlewaretoken": csrf_token,
"username": username,
"password": password,
}
headers = {
'Cookie': f'csrftoken={csrf_token}',
}
response = requests.post(url, data=data, headers=headers)
And it solved the issue.