Django登出POST请求返回403错误,CSRF相关问题排查
解决方案
一、类视图的CSRF配置(正确用法)
1. 启用CSRF保护(优先方案)
类视图的CSRF装饰器要作用在dispatch方法上(这是所有请求的入口),用method_decorator实现:
from django.views.decorators.csrf import csrf_protect from django.utils.decorators import method_decorator from django.views import View @method_decorator(csrf_protect, name='dispatch') class LogoutView(View): def post(self, request): request.session.flush() return JsonResponse({'status': 'success'})
如果是DRF的APIView,需确保认证类包含SessionAuthentication(DRF对session认证的视图会自动启用CSRF验证):
from rest_framework.views import APIView from rest_framework.authentication import SessionAuthentication class LogoutView(APIView): authentication_classes = [SessionAuthentication] def post(self, request): request.session.flush() return Response({'status': 'success'})
2. 豁免CSRF(仅应急,不推荐)
如果必须豁免,同样装饰dispatch方法:
from django.views.decorators.csrf import csrf_exempt from django.utils.decorators import method_decorator @method_decorator(csrf_exempt, name='dispatch') class LogoutView(View): def post(self, request): # 登出逻辑
二、前端正确传递CSRF Token(核心问题)
后端返回403,大概率是前端没按Django要求传递Token。Django接受三种方式,AJAX请求优先认X-CSRFToken请求头:
- 获取CSRF Token:从Cookie中读取
csrftoken(可使用js-cookie库简化操作) - 发送请求时带上Token:必须添加
credentials: 'include'确保Cookie被传递
Axios示例:
import Cookies from 'js-cookie'; import axios from 'axios'; // 全局配置自动携带CSRF头 axios.defaults.xsrfCookieName = 'csrftoken'; axios.defaults.xsrfHeaderName = 'X-CSRFToken'; axios.defaults.withCredentials = true; // 等价于credentials: include // 登出请求 const handleLogout = async () => { try { await axios.post('/api/logout/'); // 处理登出后逻辑 } catch (err) { console.error(err); } };
原生Fetch示例:
const csrftoken = Cookies.get('csrftoken'); fetch('/api/logout/', { method: 'POST', headers: { 'X-CSRFToken': csrftoken, 'Content-Type': 'application/json', }, credentials: 'include', // 必须加,否则浏览器不发送Cookie });
三、LoginView未触发CSRF验证的原因及修复
之前LoginView没验证CSRF,大概率是:
- 视图继承DRF的
APIView但未配置SessionAuthentication,DRF默认对非session认证视图豁免CSRF - 视图被隐式添加了
csrf_exempt装饰器
修复方式:给LoginView也加上csrf_protect装饰器(同第一部分的类视图装饰方式),同时确保前端正确传递Token,即可触发正常验证。
四、为什么GET请求登出能工作?
Django对GET请求默认跳过CSRF验证,但登出用GET存在安全风险(恶意网站可通过诱导点击触发登出),所以强烈建议用POST+CSRF验证的方案。
内容的提问来源于stack exchange,提问作者Hamzah Al-Hamadani
相关产品推荐
相关产品推荐

