I've been trying to solve this issue in various ways for awhile now, but every answer I have seen on here has not worked for me yet. I am running React (and Redux) on my localhost:3000, and Django on localhost:8000. I'm very still new to this, but I have seen posts where people have said to include csrf token in the header where the axios post is taken place, but that hasn't worked for me. I've also tried fiddling with settings.py, but none of that has worked as well. This is what I had before researching just to hopefully get a base. Thank you!
Here is my /actions/auth.js
import axios from 'axios';
import {
LOGIN_SUCCESS,
LOGIN_FAIL,
USER_LOADED_SUCCESS,
USER_LOADED_FAIL,
} from './types';
// login function
export const login = (email, password) => async (dispatch) => {
const config = {
headers: {
'Content-Type': 'application/json',
},
};
const body = JSON.stringify({ email, password });
try {
const response = await axios.post(
`${process.env.REACT_APP_API_URL}/auth/jwt/create/`,
body,
config
);
dispatch({
type: LOGIN_SUCCESS,
payload: response.data,
});
dispatch(load_user());
} catch (err) {
dispatch({
type: LOGIN_FAIL,
});
}
};
settings.py
"""
from pathlib import Path
import os
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'api',
'rest_framework',
'djoser',
]
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',
]
ROOT_URLCONF = 'total_weather_backend.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'build')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'total_weather_backend.wsgi.application'
# Database
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'total_weather_backend',
# REMOVE - Not sure if needed (3, 612)
# 'USER': 'postgres',
# 'PASSWORD': '',
# 'HOST': 'localhost',
}
}
# Password validation
# https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.0/howto/static-files/
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'build/static'),
)
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated'
],
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
}
SIMPLE_JWT = {
'AUTH_HEADER_TYPES': ('JWT',),
}
DJOSER = {
'LOGIN_FIELD': 'email',
'USER_CREATE_PASSWORD_RETYPE': True,
'USERNAME_CHANGED_EMAIL_CONFIRMATION': True,
'PASSWORD_CHANGED_EMAIL_CONFIRMATION': True,
'SEND_CONFIRMATION_EMAIL': True,
'SET_PASSWORD_RETYPE': True,
'PASSWORD_RESET_CONFIRM_URL': 'password/reset/confirm/{uid}/{token}',
'ACTIVATION_URL': 'activate/{uid}/{token}',
'SEND_ACTIVATION_EMAIL': True,
'SERIALIZERS': {
'user_create': 'djoser.serializers.UserCreateSerializer',
'user': 'djoser.serializers.UserSerializer',
'user_delete': 'djoser.serializers.UserDeleteSerializer',
}
}
# Default primary key field type
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
AUTH_USER_MODEL = 'api.User'
/views/users.py
from rest_framework.response import Response
from rest_framework import status, generics
from rest_framework.authtoken.models import Token
from ..serializers import UserCreateSerializer
from django.contrib.auth import authenticate, login, logout
class SignUp(generics.CreateAPIView):
# Override the authentication/permissions classes so this endpoint
# is not authenticated & we don't need any permissions to access it.
authentication_classes = ()
permission_classes = ()
def post(self, request):
# Create the user using the UserSerializer
created_user = UserCreateSerializer(data=request.data['user'])
# Check user is valid
if created_user.is_valid():
# Save the user and send back a response!
created_user.save()
return Response({'user': created_user.data}, status=status.HTTP_201_CREATED)
else:
return Response(created_user.errors, status=status.HTTP_400_BAD_REQUEST)
class SignIn(generics.CreateAPIView):
# Override the authentication/permissions classes so this endpoint
# is not authenticated & we don't need any permissions to access it.
authentication_classes = ()
permission_classes = ()
def post(self, request):
data = request.data['user']
# use django authenticate to verify password and email match
user = authenticate(
request, email=data['email'], password=data['password'])
# Is our user is successfully authenticated...
if user is not None:
login(request, user)
# use django generate a token and save it to user
Token.objects.filter(user=user).delete()
token = Token.objects.create(user=user)
user.token = token.key
user.save()
# return the user with their id, email and token
return Response({
'user': {
'id': user.id,
'email': user.email,
'token': token.key
}
})
else:
return Response({'msg': 'The username and/or password is incorrect.'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
class SignOut(generics.DestroyAPIView):
def delete(self, request):
user = request.user
# Remove this token from the user
Token.objects.filter(user=user).delete()
user.token = None
user.save()
# Logout will remove all session data
logout(request)
return Response(status=status.HTTP_204_NO_CONTENT)
class ChangePassword(generics.UpdateAPIView):
def patch(self, request):
user = request.user
old_pw = request.data['passwords']['old']
new_pw = request.data['passwords']['new']
# This is included with the Django base user model
# https://docs.djangoproject.com/en/3.2/ref/contrib/auth/#django.contrib.auth.models.User.check_password
if not user.check_password(old_pw):
return Response({'msg': 'Wrong password'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
# set_password will also hash the password
# https://docs.djangoproject.com/en/3.2/ref/contrib/auth/#django.contrib.auth.models.User.set_password
user.set_password(new_pw)
user.save()
return Response(status=status.HTTP_204_NO_CONTENT)
urls.py
from django.contrib import admin
from django.urls import path, include, re_path
from django.views.generic import TemplateView
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('auth/', include('djoser.urls')),
path('auth/', include('djoser.urls.jwt')),
path('', include('api.urls')),
]+ static(settings.MEDIA_URL, document_root = settings.MEDIA_ROOT)
urlpatterns += [re_path(r'^.*', TemplateView.as_view(template_name='index.html'))]
Here is the error in the terminal
Forbidden (CSRF token missing.): /'http://localhost:8000;/auth/jwt/create/
[19/Dec/2021 21:56:05] "POST /'http://localhost:8000;/auth/jwt/create/ HTTP/1.1" 403 2506
In javascript you must first read the csrf cookie:
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const csrftoken = getCookie('csrftoken');
And you should then set the X-CSRFToken
header like so:
const config = {
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken,
},
};
It's all superbly described in documentation: https://docs.djangoproject.com/en/4.0/ref/csrf/moddle
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.