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

如何在DRF中为无登录UUID Cookie用户识别实现CSRF防护

匿名公告板(React+DRF)的CSRF防护最佳实现方案

核心逻辑

Django自带的CsrfViewMiddleware会自动完成CSRF Token的生成、存储与匹配验证,针对你的匿名用户场景,只需适配前端获取Token的流程即可,无需手动实现复杂的Token校验逻辑。


1. Django端基础配置

确保settings.py中启用CSRF中间件并配置适配参数:

# settings.py
MIDDLEWARE = [
    # ...其他中间件
    'django.middleware.csrf.CsrfViewMiddleware',  # 必须保留,核心CSRF防护中间件
    # ...你的自定义user_id中间件
]

# CSRF Cookie适配配置
CSRF_COOKIE_SAMESITE = 'Lax'  # 兼容同域/跨域场景,防止CSRF攻击
CSRF_COOKIE_HTTPONLY = False  # 允许前端读取Cookie中的Token值
CSRF_TRUSTED_ORIGINS = ['http://你的React域名']  # 跨域部署时添加,同域可省略

2. 后端提供CSRF Token接口

添加一个简单视图,用于向前端返回当前用户的CSRF Token:

# views.py
from django.middleware.csrf import get_token
from rest_framework.decorators import api_view
from rest_framework.response import Response

@api_view(['GET'])
def get_csrf_token(request):
    # 直接从Django的CSRF机制中获取当前用户的Token
    return Response({'csrfToken': get_token(request)})

配置对应路由:

# urls.py
from django.urls import path
from . import views

urlpatterns = [
    # ...其他业务接口路由
    path('api/csrf-token/', views.get_csrf_token, name='get_csrf_token'),
]

3. React前端集成CSRF Token

在页面初始化时获取Token,并在发送修改类请求时携带:

import { useEffect, useState } from 'react';

function AnnouncementBoard() {
  const [csrfToken, setCsrfToken] = useState('');
  const [content, setContent] = useState('');

  // 页面加载时自动获取CSRF Token
  useEffect(() => {
    fetch('/api/csrf-token/')
      .then(res => res.json())
      .then(data => setCsrfToken(data.csrfToken));
  }, []);

  // 发布公告的请求示例
  const publishAnnouncement = async () => {
    try {
      await fetch('/api/announcements/', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-CSRFToken': csrfToken  // 携带CSRF Token到请求头
        },
        body: JSON.stringify({ content })
      });
      setContent('');
    } catch (err) {
      console.error('发布失败:', err);
    }
  };

  return (
    <div className="board">
      <textarea 
        value={content}
        onChange={(e) => setContent(e.target.value)}
        placeholder="输入公告内容..."
      />
      <button onClick={publishAnnouncement}>发布匿名公告</button>
    </div>
  );
}

export default AnnouncementBoard;

4. 自定义中间件优化

你的当前中间件继承了SessionMiddleware,如果未使用Django的Session功能,建议改为普通中间件,减少不必要的Session处理开销:

import uuid
from django.http import HttpRequest, HttpResponse

class CustomUserIDMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request: HttpRequest) -> HttpResponse:
        response = self.get_response(request)
        # 为无user_id Cookie的用户生成UUID标识
        if not request.COOKIES.get('user_id'):
            max_age = 365 * 24 * 60 * 60
            response.set_cookie(
                'user_id',
                str(uuid.uuid4()),
                max_age=max_age,
                samesite='lax'
            )
        return response

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 01:48:19