Получение ошибки для 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). Дайте мне знать, если что-то снова будет не так.

Вернуться на верх