ReactJS与Django跨域下如何通过Axios正确传递CSRF Token?
Hey there! Let's tackle this CSRF issue you're facing while setting up user registration with React and a separate Django backend. Cross-domain CSRF handling is one of the most common pain points when working with fully decoupled stacks, but once you get the pieces aligned, it works smoothly. Here's a step-by-step breakdown to fix it:
Django's CSRF protection relies on matching a token stored in a cookie with a token sent in the request header. When your React app is on a different domain, even with withCredentials: true, a few critical pieces are missing:
- Django might not trust your frontend's origin to send CSRF requests
- Your frontend isn't properly fetching and attaching the CSRF token to the registration request
- Cross-origin cookie rules might be blocking the CSRF cookie from being stored or sent
First, let's get Django set up to accept cross-origin requests and trust your frontend:
Install & Configure CORS Headers
Django doesn't handle CORS out of the box, so we'll use the django-cors-headers package:
- Install it:
pip install django-cors-headers - Update your
settings.py:# Add corsheaders to INSTALLED_APPS INSTALLED_APPS = [ # ... other existing apps 'corsheaders', ] # Add CorsMiddleware BEFORE CommonMiddleware (order matters!) MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', # Keep CsrfViewMiddleware enabled - it's required for CSRF protection 'django.middleware.csrf.CsrfViewMiddleware', # ... other middleware ] # Allow your React app's origin (replace with your actual frontend URL) CORS_ALLOWED_ORIGINS = [ "http://localhost:3000", ] # Allow credentials (cookies) to be sent cross-domain CORS_ALLOW_CREDENTIALS = True # Trust your frontend's origin for CSRF (critical for Django 3.2+) CSRF_TRUSTED_ORIGINS = [ "http://localhost:3000", ] # Optional: Skip for local dev - set only if using custom domains # SESSION_COOKIE_DOMAIN = ".yourdomain.com" # CSRF_COOKIE_DOMAIN = ".yourdomain.com"
(Optional) Add a Dedicated CSRF Token Endpoint
While you can fetch the CSRF cookie via any GET request to Django, creating a dedicated endpoint makes the process explicit. Add this to your views.py:
from django.http import JsonResponse from django.middleware.csrf import get_token def get_csrf_token(request): # This view sets the CSRF cookie and returns the token value return JsonResponse({'csrfToken': get_token(request)})
Then map it in urls.py:
from django.urls import path from .views import get_csrf_token, register_user # Your existing registration view urlpatterns = [ path('api/get-csrf/', get_csrf_token, name='get_csrf'), path('api/register/', register_user, name='register'), # ... other URLs ]
Now let's configure React to fetch the CSRF token and attach it to your registration request:
Global Axios Configuration
Set up Axios to automatically handle credentials and CSRF tokens:
import axios from 'axios'; // Configure Axios globally axios.defaults.withCredentials = true; axios.defaults.baseURL = 'http://localhost:8000'; // Replace with your Django API URL // Add an interceptor to automatically attach the CSRF token to requests axios.interceptors.request.use((config) => { // Extract the CSRF token from browser cookies const csrfToken = document.cookie .split('; ') .find(row => row.startsWith('csrftoken=')) ?.split('=')[1]; if (csrfToken) { config.headers['X-CSRFToken'] = csrfToken; } return config; }, (error) => { return Promise.reject(error); });
Handle Registration Request
Make sure to fetch the CSRF token first (this ensures the cookie is set in the browser) before sending your registration data:
const handleRegister = async (formData) => { try { // First, fetch the CSRF token to set the cookie in the browser await axios.get('/api/get-csrf/'); // Then send the registration request with your user data const response = await axios.post('/api/register/', formData); console.log('Registration successful!', response.data); // Handle success (e.g., redirect to login page) } catch (error) { console.error('Registration failed:', error.response?.data || error.message); // Handle error (e.g., display error message to the user) } };
- Browser Third-Party Cookie Blocking: Some browsers (like Chrome) block third-party cookies by default in non-incognito mode. For development, you can temporarily allow this in your browser settings.
- Middleware Order: Ensure
CorsMiddlewarecomes beforeCommonMiddlewarein your Django settings—this is critical for CORS headers to be applied correctly. - DRF Session Authentication: If you're using Django Rest Framework's
SessionAuthentication, make sure your registration view is protected by CSRF (it should be by default ifCsrfViewMiddlewareis enabled).
That should get your registration request working smoothly! Let me know if you hit any snags along the way.
内容的提问来源于stack exchange,提问作者purolor

