如何在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
相关产品推荐
相关产品推荐

