Django Auth提示CSRF Cookie未设置,Next.js登录请求报错求助
问题分析与解决方案
核心问题根源
你遇到的"CSRF cookie not set"错误,本质是跨域请求时未正确携带CSRF cookie,同时Django的CSRF验证要求两个条件:请求头带X-CSRFToken,且请求中包含CSRF cookie,二者缺一不可。你的代码存在两个关键疏漏:
- 跨域请求未开启
withCredentials,导致浏览器不会向Django发送CSRF cookie - 未确保浏览器在发送POST请求前已获取到CSRF cookie
分步解决方案
第一步:配置Django后端(必须)
安装并配置
django-cors-headers以支持跨域带凭证请求pip install django-cors-headers修改
settings.py:INSTALLED_APPS = [ # 其他已安装应用 'corsheaders', ] MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', # 确保CsrfViewMiddleware在中间件列表中 'django.middleware.csrf.CsrfViewMiddleware', # 其他中间件 ] # 允许跨域带凭证 CORS_ALLOW_CREDENTIALS = True # 信任你的Next.js域名 CORS_ORIGIN_WHITELIST = ['http://localhost:3000'] # 允许该域名的CSRF请求 CSRF_TRUSTED_ORIGINS = ['http://localhost:3000']新增获取CSRF cookie的视图(确保浏览器能拿到cookie)
在views.py中添加:from django.http import JsonResponse from django.middleware.csrf import get_token def get_csrf_token(request): return JsonResponse({'csrfToken': get_token(request)})在
urls.py中配置路由:from django.urls import path from .views import get_csrf_token urlpatterns = [ # 其他路由 path('api/get-csrf-token/', get_csrf_token, name='get_csrf_token'), ]
第二步:修改前端Login函数
修改后的代码解决了跨域带凭证、提前获取CSRF cookie的问题:
export const login = (username, email, password) => async dispatch => { 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(); if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } // 提前发送GET请求获取CSRF cookie await axios.get('http://localhost:8000/api/get-csrf-token/', { withCredentials: true }); const csrftoken = getCookie('csrftoken'); console.log(csrftoken); const config = { headers: { 'Content-Type': 'application/json', }, withCredentials: true // 跨域请求携带cookie }; const config_two = { headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'X-CSRFToken': csrftoken, }, withCredentials: true // 必须开启,否则浏览器不发送CSRF cookie }; console.log(config_two) const body = JSON.stringify({ email, password }); const body_two = JSON.stringify({ username, password }); try { const res = await axios.post(`http://localhost:8000/auth/jwt/create/`, body, config); const res_two = await axios.post(`http://localhost:8000/api-token-auth/`, body_two, config_two); dispatch({ type: LOGIN_SUCCESS, payload: res.data }); dispatch(load_user()); toast.success("You are logged in"); } catch (err) { // 打印具体错误信息便于排查 console.error(err.response?.data || err.message); toast.error("Something went wrong"); dispatch({ type: LOGIN_FAIL }) } };
可选优化:全局配置Axios
避免每个请求都重复设置withCredentials,可以全局配置Axios:
// 在utils/axios.js中创建实例 import axios from 'axios'; const axiosInstance = axios.create({ withCredentials: true, }); export default axiosInstance;
之后在login函数中用axiosInstance代替原生axios即可。
内容的提问来源于stack exchange,提问作者denysenkod
相关产品推荐
相关产品推荐

