Возникновение проблемы 302 редиректа при отправке формы в приложении React/Django, поскольку вызов API перенаправляется

В моем приложении Django/React я хочу, чтобы пользователь был зарегистрирован для успешной отправки запроса к API.

Я успешно вошел в систему с помощью google и считаю, что передаю все правильные данные в backend api для его вызова.

Я настроил CORS, убедился, что мои CSRF-токены совпадают, использую @login_required в представлении Django, использую "credentials: 'include'" в api вызове, и исчерпал как ChatGPT, так и свой собственный поиск в интернете, чтобы решить проблему.

Из моего файла Conversation.jsx я хочу вызвать /api/ask_new_york из app/views.py. Даже при входе в систему я получаю ответ 302.

Вот весь, как мне кажется, релевантный код и вывод:

settings.py:



MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'allauth.account.middleware.AccountMiddleware',
]

# CORS settings
CORS_ALLOW_ALL_ORIGINS = True
CORS_ALLOW_CREDENTIALS = True

# CSRF settings
CSRF_TRUSTED_ORIGINS = [
    'http://localhost:3000',
    'http://localhost:8000',
    'http://127.0.0.1:8000',
    'http://localhost'
]

# Disable CSRF cookies only if needed
CSRF_COOKIE_SECURE = False 

LOGIN_REDIRECT_URL = '/'
LOGIN_URL = '/login/'
LOGOUT_REDIRECT_URL = '/'

app/views.py:


@csrf_exempt
def get_csrf_token(request):
    csrf_token = get_token(request)
    return JsonResponse({'csrf_token': csrf_token})

@login_required
def ask_new_york(request):
    if request.method == 'POST':
        try:
            data = json.loads(request.body.decode('utf-8'))
            input_value = data.get('input_value'
     

users/views.py: Здесь происходит создание пользователей (это весь файл)

from django.contrib.auth import get_user_model
from django.conf import settings
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from google.oauth2 import id_token
from google.auth.transport import requests as google_requests
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from .serializers import UserSerializer
from django.db import IntegrityError

User = get_user_model()

@api_view(['POST'])
@csrf_exempt
def google_login(request):
    if request.method == 'POST':
        try:
            token = request.data.get('token')
            if not token:
                return JsonResponse({'error': 'No token provided'}, status=400)

            # Verify the token using Google's API
            idinfo = id_token.verify_oauth2_token(token, google_requests.Request(), settings.GOOGLE_CLIENT_ID)

            # If token is valid, get the user info
            email = idinfo['email']
            name = idinfo.get('name', '')

            # Check if the user exists, if not, create a new user
            user, created = User.objects.get_or_create(email=email, defaults={'username': email, 'first_name': name})

            if created:
                user.set_unusable_password()  # If user is created, ensure no password is set
                user.save()

            # Return user info
            return JsonResponse({'email': user.email, 'name': user.first_name})

        except ValueError:
            return JsonResponse({'error': 'Invalid token'}, status=400)

        except IntegrityError:
            # Handle the case where the email already exists
            return JsonResponse({'error': 'User with this email already exists'}, status=400)

    return JsonResponse({'error': 'Invalid request method'}, status=400)


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def user_detail(request):
    user = request.user
    serializer = UserSerializer(user)
    return Response(serializer.data)

LoginSignUpPage.jsx: Фронтенд-страница, на которой пользователь фактически регистрируется. (это весь файл)

import React, { useContext, useEffect, useState } from 'react';
import { GoogleLogin } from '@react-oauth/google';
import { useNavigate } from 'react-router-dom';
import { jwtDecode } from "jwt-decode";
import AuthContext from './AuthContext';
import axios from 'axios';
import { getCsrfToken } from './csrfToken'; // Import the utility

const LoginSignupPage = () => {
  const { setAuthUser } = useContext(AuthContext);
  const navigate = useNavigate();
  const [csrfToken, setCsrfToken] = useState('');

  useEffect(() => {
    const token = getCsrfToken(); // Use the centralized function to get CSRF token
    setCsrfToken(token);
    console.log("CSRF token set as:", token);
  }, []);

  const handleLoginSuccess = async (response) => {
    try {
      const decoded = jwtDecode(response.credential); // Decode JWT
      const { email, name } = decoded;
  
      // Send token to backend for verification and authentication
      const res = await axios.post(
        'http://localhost:8000/api/google-login/',
        { token: response.credential },
        {
          headers: {
            'X-CSRFToken': csrfToken, // Include the CSRF token in the headers
          },
        }
      );
  
      const user = {
        email: res.data.email,
        name: res.data.name,
        created_at: res.data.created_at,
      };
  
      console.log(user); // Log user info
  
      // Save user data in context or global state
      setAuthUser(user);
  
      // Redirect to home page after successful login
      navigate('/');
    } catch (error) {
      console.error('Login Failed:', error);
    }
  };
  
  const handleLoginFailure = (error) => {
    console.log('Login Failed:', error);
  };

  return (
    <div>
      <h1>Login</h1>
      <GoogleLogin onSuccess={handleLoginSuccess} onError={handleLoginFailure} />
    </div>
  );
};

export default LoginSignupPage;

Conversation.jsx: Домашняя страница, на которой пользователь отправляет текст в API, обрабатываемый в handleSubmit. Здесь также есть обработка ошибок и компоненты фронт-энда, которые выполняют handleSubmit при нажатии.

import { getCsrfToken } from './csrfToken';

useEffect(() => {
    const token = getCsrfToken(); // Use the centralized function to get CSRF token
    setCsrfToken(token);
    console.log("CSRF token set as:", token);
  }, []);


const handleSubmit = async (e) => {
try {
      let headers = {
        'X-CSRFToken': csrfToken,
        'Content-Type': 'application/json',
      };
response = await fetch("http://localhost:8000/api/ask_new_york/", {
          method: "POST", // Specify POST method
          headers: headers,
          credentials: 'include', // Ensures cookies are sent with the request
          body: JSON.stringify({ input_value: inputValue }),
        });
      }

csrfToken.js: Получает csrftoken (это весь файл)

export const getCookie = (name) => {
    const value = `; ${document.cookie}`;
    console.log(value)
    const parts = value.split(`; ${name}=`);
    if (parts.length === 2) return parts.pop().split(';').shift();
  };
  
  export const getCsrfToken = () => {
    return getCookie('csrftoken'); // Adjust the name if your cookie is named differently
  };
  

В моей веб-консоли файлы csrfToken.js, LoginSignUpPage.jsx и Conversation.jsx регистрируют csrftoken, который у них есть, и все они одинаковы. При входе в систему и выполнении handleSubmit в Conversation.jsx я получаю следующие ошибки: В Google Chrome:

Error submitting data: SyntaxError: Unexpected token '<', "<!doctype "... is not valid JSON

Я полагаю, что он получает html страницы /login, на которую хочет перенаправить пользователя, даже если он вошел в систему. Возможно, здесь я ошибаюсь.

В моем внутреннем терминале:

[11/Sep/2024 21:35:31] "POST /api/ask_new_york/ HTTP/1.1" 302 0
[11/Sep/2024 21:35:31] "GET /login/?next=/api/ask_new_york/ HTTP/1.1" 200 644.

Я не знаю, почему происходит ошибка 302.

Экстра:

[11/Sep/2024 21:35:22] "OPTIONS /api/google-login/ HTTP/1.1" 200 0
[11/Sep/2024 21:35:22] "POST /api/google-login/ HTTP/1.1" 200 47

Вход в систему Google работает нормально.

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