Получение ошибки для django и react native code Forbidden (CSRF token missing.):
Я работаю над бэкендом Django для обработки некоторых манипуляций с данными, в частности, добавления и удаления данных. Мой код отлично работает при тестировании с помощью Postman, но я сталкиваюсь с ошибкой 403 Forbidden при попытке получить доступ к конечной точке /bookings/remove/ из моего фронтенда React Native.
Вот сообщение об ошибке, которое я получаю:
Forbidden (CSRF token missing.): /bookings/remove/ "POST /bookings/remove/?booking_id=148/ HTTP/1.1" 403
Интересно, что все остальные конечные точки работают нормально без каких-либо проблем, связанных с CSRF. Только эта конкретная конечная точка вызывает проблемы.
Django Backend
У меня следующие настройки для cors:
INSTALLED_APPS = [
'corsheaders',
"all other apps"
]
SESSION_COOKIE_SECURE = False
SESSION_COOKIE_SAMESITE = None
SESSION_COOKIE_AGE = 1209600
CORS_ALLOW_ALL_ORIGINS = True
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
}
и моя конечная точка, для которой я получаю ошибку:
@api_view(["POST"])
@permission_classes([IsAuthenticated])
@csrf_exempt
def cancel_the_booking(request, booking_id):
try:
if not booking_id:
return Response({"error": "Booking ID is required"}, status=status.HTTP_400_BAD_REQUEST)
booking = Booking.objects.get(booking_id=booking_id)
if booking.host_id != request.user.id:
return Response({"error": "You are not authorized to cancel this booking", "host": request.user.id}, status=status.HTTP_403_FORBIDDEN)
for date_price in booking.dates_price.all():
AdSpaceDates.objects.create(
ad_space=booking.space_id,
available_from=date_price.available_from,
available_to=date_price.available_to,
price=date_price.price
)
booking.delete()
return Response({"success": "Booking cancelled and dates are now available again"}, status=status.HTTP_200_OK)
except Booking.DoesNotExist:
return Response({"error": "Booking does not exist"}, status=status.HTTP_404_NOT_FOUND)
except Exception as e:
return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
my urls.py для приложения Booking
path('remove/<int:booking_id>/', cancel_the_booking , name="cancel_the_booking")
и мой проект urls.py -
path("bookings/", include("Bookings.urls")),
для повторного получения csrf
@api_view(["GET"])
@ensure_csrf_cookie
def get_csrf_token(request):
csrf_token = get_token(request)
return JsonResponse({'csrfToken': csrf_token})
path('api/get-csrf-token/', get_csrf_token, name='get_csrf_token'),
React Native code
const getCsrfToken = async () => {
try {
const response = await Api.get('/api/get-csrf-token/');
return response.data.csrfToken;
} catch (error) {
console.error('Error fetching CSRF token', error);
return null;
}
};
const handleConfirmButton = (booking) => {
Alert.alert(
'Cancel Booking',
'Are you sure you want to cancel this booking?',
[
{
text: 'No',
onPress: () => console.log('Cancel Pressed'),
style: 'cancel',
},
{
text: 'Yes',
onPress: () => handleBookingCancellation(booking),
},
],
{ cancelable: false }
);
};
const handleBookingCancellation = async (booking) => {
try {
const csrfToken = await getCsrfToken();
if (!csrfToken) {
Alert.alert('Error', 'Failed to fetch CSRF token');
return;
}
const response = await axios.post(`http://127.0.0.1:8000/bookings/remove/?booking_id=${booking.booking_id}/`, {
headers: {
'Authorization': `Bearer ${await SecureStore.getItemAsync('access')}`,
'X-CSRFToken': csrfToken
},
});
Alert.alert("Booking Cancelled", `Booking ID: ${booking.booking_id}`);
console.log(response);
} catch (error) {
console.error('Error cancelling booking', error);
Alert.alert('Error', 'There was an error cancelling the booking');
}
};
<TouchableOpacity style={styles.confirmButton } onPress={() => handleConfirmButton(item)} >
<Text style={styles.viewAllText}>Cancel Booking</Text>
<AntDesign name="delete" size={24} color="white" style={styles.icon} />
</TouchableOpacity>
Я пробовал несколько подходов к решению ошибки 403 Forbidden (CSRF token missing) именно для конечной точки /bookings/remove/:
- Получение CSRF-токена:
Выполнили выборку CSRF-токена из бэкенда с помощью выделенной конечной точки (/api/get-csrf-token/). Получение токена работает корректно и возвращает корректный CSRF-токен.
- Отправка CSRF-токена в запросах:
Изменили запрос на выборку в React Native, чтобы включить в заголовки токен CSRF. Ожидается, что бэкэнд примет запрос и обработает отмену бронирования.
- Настройка параметров Django:
Убедитесь, что CSRF_TRUSTED_ORIGINS и CORS_ALLOWED_ORIGINS включают URL-адреса фронтенда. Включено CORS_ALLOW_ALL_ORIGINS.
- Изменение метода и заголовков HTTP:
Пробовали использовать методы POST и DELETE. Включил необходимые заголовки (Authorization, Content-Type и X-CSRFToken).
Несмотря на эти усилия, запрос к /bookings/remove/ постоянно приводит к ошибке 403 Forbidden (CSRF token missing). Другие конечные точки работают корректно без этой проблемы, что сбивает с толку.
Я ожидал, что запрос будет успешным, отменит бронирование и вернет ответ с подтверждением, но он потерпел неудачу на этапе проверки CSRF.
Я ожидал, что после правильной выборки и включения CSRF-токена в заголовки запроса бэкэнд проверит токен и позволит продолжить запрос на отмену бронирования, не возвращая ошибку 403 Forbidden.
при этом все работает нормально с postman.
Прежде всего, Если вы хотите использовать
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
'rest_framework_simplejwt.authentication.JWTAuthentication',
]
поэтому вам больше не нужны настройки SESSION (удалите их), а также используйте один из JWT или Token для цикла аутентификации. Но что касается вашей проблемы, я думаю, что она возникает из-за вашего промежуточного ПО, вы поместили его в неправильное место. CORS middleware
должен быть заменен перед COMMON middleware
, а не в верхней части всех других промежуточных программ. Измените его место (читайте документацию CORS). Дайте мне знать, если что-то снова будет не так.