Django接收Chrome扩展POST请求时出现CSRF cookie未设置错误
Django + Chrome扩展 CSRF认证失败问题解决指南
问题概述
开发Chrome扩展+Django的密码管理器时,提交表单数据到Django后端始终返回Forbidden (CSRF cookie not set.),已确认Cookie中存在csrftoken且请求携带了CSRF令牌,但问题依旧。
针对性解决建议
1. 修复请求数据格式不匹配
当前请求头设置Content-Type: application/x-www-form-urlencoded,但发送的是JSON格式数据,Django的request.POST无法解析JSON,导致CSRF验证逻辑触发失败。
修改方案:
将请求改为JSON格式,同时调整Django视图解析逻辑:
前端(content-script.js)修改:
export async function axiosaddCredentialsToDatabase(email,password,url){ const token = await getCsrfToken() const axios = require('axios') axios.post('http://localhost:8000/add',{email,password,website: url},{ headers: { 'Content-Type': 'application/json', 'X-CSRFToken': token, 'X-Requested-With': 'XMLHttpRequest', }, withCredentials:true }).then((response)=>{ console.log(response) }).catch(err => console.error(err)) }
Django视图修改:
import json from django.http import JsonResponse from django.views.decorators.csrf import ensure_csrf_cookie from django.contrib.auth.decorators import login_required @login_required @ensure_csrf_cookie def add(request): if request.method == "POST": data = json.loads(request.body) website = data.get('website') username = data.get('email') password = data.get('password') encryptedPass = cryptography.crypto(password) credentials = Credentials.objects.create(email=username, password=encryptedPass) # 使用get_or_create简化逻辑 website_obj, created = Website.objects.get_or_create(user=request.user, name=website) website_obj.credentials.add(credentials) if request.headers.get('X-Requested-With') == 'XMLHttpRequest': return JsonResponse({'message':'Credentials Add'}) return redirect('add') return render(request,'add.html')
2. 优化CSRF令牌获取逻辑
Chrome扩展的content script运行在隔离环境,直接读取Cookie可能存在权限限制,建议从响应头的set-cookie中提取令牌:
export async function getCsrfToken(){ const axios = require('axios') const response = await axios.get('http://localhost:8000/get-csrf-token',{withCredentials:true}) // 从set-cookie头提取csrftoken const cookies = response.headers['set-cookie'] if (cookies) { const csrfEntry = cookies.find(c => c.startsWith('csrftoken=')) if (csrfEntry) { return csrfEntry.split('=')[1].split(';')[0] } } // 回退到接口返回的token return response.data.csrfToken }
3. 简化Django CSRF配置
移除冗余且冲突的配置,确保配置符合Django规范:
# settings.py ALLOWED_HOSTS = ['localhost', '127.0.0.1'] CORS_ALLOW_CREDENTIALS = True CORS_ALLOWED_ORIGINS = [ "http://localhost:8000", # 必须添加Chrome扩展的ID作为源,格式:chrome-extension://[你的扩展ID] ] CSRF_COOKIE_SAMESITE = 'None' SESSION_COOKIE_SAMESITE = 'None' CSRF_COOKIE_SECURE = False # 生产环境开启HTTPS后改为True CSRF_COOKIE_HTTPONLY = False CSRF_TRUSTED_ORIGINS = [ "http://localhost:8000", # 同样添加Chrome扩展ID ]
4. 验证请求携带的Cookie
在Chrome开发者工具Network标签中,检查POST请求的Request Headers:
- 确认
Cookie字段包含csrftoken - 确认
X-CSRFToken头的值与Cookie中的csrftoken完全一致
内容的提问来源于stack exchange,提问作者MuhaAllAmeen
相关产品推荐
相关产品推荐

