Django无需@csrf_exempt解决CSRF cookie未设置的禁止访问问题
安全解决方案(无需
@csrf_exempt) 方案1:浏览器端页面调用(适配Django原生CSRF机制)
如果是通过Django渲染的前端页面发起请求,需遵循Django的CSRF验证流程:
- 在模板中引入CSRF Token:通过
{% csrf_token %}生成隐藏表单字段,或通过JS读取浏览器Cookie中的csrftoken值 - 发起请求时,将Token放入请求头
X-CSRFToken中
示例JS代码:
// 获取Cookie中的CSRF Token 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; } // 发起POST请求 const csrftoken = getCookie('csrftoken'); fetch('/api/calculator/score/', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrftoken, }, body: JSON.stringify(yourRequestData), }) .then(response => response.json()) .then(data => console.log(data));
注意:确保前端页面由Django视图渲染,否则浏览器无法获取CSRF Cookie。
方案2:非浏览器客户端调用(Token认证)
如果是外部脚本、服务调用接口,推荐使用Token替代CSRF验证,以Django REST Framework的TokenAuthentication为例:
- 安装并配置DRF:
- 安装依赖:
pip install djangorestframework - 在
settings.py的INSTALLED_APPS中添加:INSTALLED_APPS = [ # 其他应用 'rest_framework', 'rest_framework.authtoken', ] - 执行迁移:
python manage.py migrate
- 安装依赖:
- 为调用方用户生成Token:
- 通过Django后台创建用户,或执行命令:
python manage.py drf_create_token <用户名>
- 通过Django后台创建用户,或执行命令:
- 修改视图添加认证:
from rest_framework.decorators import api_view, authentication_classes, permission_classes from rest_framework.authentication import TokenAuthentication from rest_framework.permissions import IsAuthenticated import requests from django.http import JsonResponse @api_view(['POST']) @authentication_classes([TokenAuthentication]) @permission_classes([IsAuthenticated]) def post_for_score(request): # DRF自动解析JSON请求体,无需手动解码 body_dict = request.data flask_url = '<<my flask/amazon url here>>' res = requests.post(flask_url, json=body_dict) if res.status_code == 200: return JsonResponse(res.json()) else: return JsonResponse({"error": str(res.content)}) - 调用接口时携带Token:
curl -X POST http://127.0.0.1:8000/api/calculator/score/ \ -H "Content-Type: application/json" \ -H "Authorization: Token 你的Token值" \ -d '{"key": "value"}'
方案3:受限来源的CSRF豁免(仅信任特定调用方)
如果仅需对指定信任来源放开CSRF,可在视图中添加来源校验后再豁免:
from django.views.decorators.csrf import csrf_exempt from django.http import JsonResponse import json import requests def post_for_score(request): # 校验请求来源是否在信任列表 allowed_origins = [ '<<my flask/amazon url here>>', "http://127.0.0.1:8000", "http://localhost:8000" ] origin = request.META.get('HTTP_ORIGIN') if origin not in allowed_origins: return JsonResponse({"error": "Invalid origin"}, status=403) body_unicode = request.body.decode('utf-8') body_dict = json.loads(body_unicode) flask_url = '<<my flask/amazon url here>>' res = requests.post(flask_url, json=body_dict) if res.status_code == 200: return JsonResponse(res.json()) else: return JsonResponse({"error": str(res.content)}) # 仅对通过来源校验的请求豁免CSRF post_for_score = csrf_exempt(post_for_score)
注:该方案安全性弱于Token认证,仅适用于完全信任的调用方。
补充:为什么CSRF_TRUSTED_ORIGINS未生效?
CSRF_TRUSTED_ORIGINS的作用是允许跨域请求携带CSRF Cookie,而非直接豁免CSRF验证。即使配置了该参数,请求方仍需携带CSRF Token或Cookie,否则依然会触发Forbidden错误。
内容的提问来源于stack exchange,提问作者dl_atl
相关产品推荐
相关产品推荐

