You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+Django生产环境Create接口CSRF Token异常求助

问题描述

开发环境中CSRF Cookie可正常设置,但生产环境调用Create接口创建帖子时,报错CSRF Failed: CSRF token from the 'X-Csrftoken' HTTP header has incorrect length.。登录、注册等其他POST请求正常,推测问题出在Django的Create方法。

另外,登录后基于会话认证,生产环境开发者工具Application标签中看不到session_id和csrf(推测是安全策略导致),但请求失败后查看Network标签,发现X-Csrftoken为undefined,而Cookie中包含csrftoken和session_id。仅生产环境出现该问题,开发环境无异常。


相关代码

后端(views.py)

class CheckAuthenticated(views.APIView):
    def get(self, request):
        if request.user.is_authenticated:
            return Response("Authenticated")
        else:
            return Response("Not Authenticated",status=401)
    
class PostView(viewsets.ModelViewSet):
    serializer_class = serializer.PostSerializer

    def get_queryset(self):
        queryset = models.Post.objects.all()
        return queryset
    
    @method_decorator(ensure_csrf_cookie)
    def create(self,request):
        authentication_classes = [SessionAuthentication]
        permissions_classes = [IsAuthenticated]
        post = serializer.PostSerializer(data=request.data)
        if post.is_valid():
            title = post.data['title']
  
            description = post.data['description']
    
            models.Post.objects.create(title=title,description=description,user=User.objects.first())
            return Response("post created successfully.")
        return Response("post creation failed.")

前端代码

let handleSubmit = (e)=>{
        e.preventDefault()
        console.log(Cookies.get('csrftoken'))
        axios.post('https://somedomain.com/posts/',post,{withCredentials:true,headers:{'X-CSRFToken':Cookies.get('csrftoken')}}).then((res)=>{
            console.log(res.data)
        }).catch((e)=>{
            console.log(e.response.data)
            console.log(Cookies.get('csrftoken'))
        })
    }
    useEffect(()=>{
        axios.get('http://127.0.0.1:8000/posts/').then((res)=>{
            setPostList(res.data)
        })
        axios.get('http://127.0.0.1:8000/csrf/',{headers:{Authorization:null},withCredentials:true})

    },[])

Django配置(settings.py)

ALLOWED_HOSTS = ['*']
ACCESS_CONTROL_ALLOW_ORIGIN = '*'
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
ACCESS_CONTROL_ALLOW_CREDENTIALS = True
ACCESS_CONTROL_ALLOW_METHODS = '*'
ACCESS_CONTROL_ALLOW_HEADERS = '*'

'''
SESSION_COOKIE_SECURE = True

CSRF_COOKIE_PATH = '/'
'''
CSRF_COOKIE_SAMESITE = 'Strict'  



CSRF_TRUSTED_ORIGINS = [ "http://127.0.0.1:3000",'http://127.0.0.1:8000','https://somedomain.com/']

SECURE_SSL_REDIRECT = True
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 60

CUSTOM_HEADERS = (
    'Access-Control-Allow-Origin',
    'Token',
    'User-Type'
)
CORS_ALLOW_HEADERS = default_headers + CUSTOM_HEADERS
CSRF_COOKIE_SAMESITE = 'none'

解决方案

1. 修复后端PostView认证配置问题

authentication_classes和permission_classes是类属性,不能写在create方法内部,否则认证逻辑不会生效。同时要修正几个细节:

class PostView(viewsets.ModelViewSet):
    serializer_class = serializer.PostSerializer
    authentication_classes = [SessionAuthentication]
    permission_classes = [IsAuthenticated]  # 注意是permission_classes,不是permissions_classes

    def get_queryset(self):
        queryset = models.Post.objects.all()
        return queryset
    
    @method_decorator(ensure_csrf_cookie)
    def create(self,request):
        post = serializer.PostSerializer(data=request.data)
        if post.is_valid():
            # 用validated_data获取验证后的安全数据,而非原始的post.data
            title = post.validated_data['title']
            description = post.validated_data['description']
            # 关联当前登录用户,而非固定取第一个用户
            models.Post.objects.create(title=title,description=description,user=request.user)
            return Response("post created successfully.")
        return Response("post creation failed.")

2. 统一前后端请求域名

生产环境下前端useEffect中的请求仍使用开发环境域名,导致跨域无法正确获取CSRF Cookie,需替换为生产环境域名:

useEffect(()=>{
    const apiDomain = 'https://somedomain.com';
    axios.get(`${apiDomain}/posts/`,{withCredentials:true}).then((res)=>{
        setPostList(res.data)
    })
    axios.get(`${apiDomain}/csrf/`,{headers:{Authorization:null},withCredentials:true})
},[])

同时确保CSRF_TRUSTED_ORIGINS中生产环境域名末尾无多余斜杠,改为'https://somedomain.com'。

3. 修复CSRF配置冲突

settings.py中重复设置了CSRF_COOKIE_SAMESITE,跨域场景下需统一配置为None(必须配合SECURE属性):

# 删除重复的CSRF_COOKIE_SAMESITE设置,保留以下配置
CSRF_COOKIE_SAMESITE = 'None'
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SAMESITE = 'None'  # 会话Cookie同步设置,避免跨域会话失效
SESSION_COOKIE_SECURE = True

4. 确保前端正确获取CSRF Token

如果依赖第三方Cookie库存在兼容问题,可改用原生方法提取CSRF Token:

function getCsrfToken() {
    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.startsWith('csrftoken=')) {
                cookieValue = decodeURIComponent(cookie.substring('csrftoken='.length));
                break;
            }
        }
    }
    return cookieValue;
}

// 在handleSubmit中替换原有写法
axios.post('https://somedomain.com/posts/',post,{
    withCredentials:true,
    headers:{'X-CSRFToken': getCsrfToken()}
})

内容的提问来源于stack exchange,提问作者Ghazi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 10:56:06