如何将Django登录页迁移至外部服务器(解决CSRF令牌缺失问题)
解决外部服务器表单提交Django登录的CSRF问题
针对跨域提交登录表单触发CSRF令牌缺失的问题,有以下几种可行方案:
方案一:主动获取Django的CSRF令牌并填充表单
Django的CSRF令牌会同时存在于登录页面的隐藏字段和响应Cookie中,外部页面可以通过JS先请求登录页面获取令牌,再添加到表单里提交:
配置Django允许跨域:
在settings.py中添加外部服务器域名到信任列表:CSRF_TRUSTED_ORIGINS = ['https://your-external-server.com'] # 替换为你的外部服务器域名 CORS_ALLOWED_ORIGINS = ['https://your-external-server.com'](需先安装
django-cors-headers:pip install django-cors-headers,并将corsheaders加入INSTALLED_APPS,添加corsheaders.middleware.CorsMiddleware到中间件列表)外部页面添加JS逻辑获取并填充令牌:
// 页面加载时获取CSRF令牌 window.addEventListener('load', function() { fetch('http://djangoserver.com/accounts/login/', { credentials: 'include' // 必须携带Cookie才能拿到csrftoken }) .then(() => { // 从Cookie提取csrftoken const csrfToken = document.cookie.split('; ') .find(row => row.startsWith('csrftoken='))?.split('=')[1]; if (csrfToken) { // 给表单添加隐藏的CSRF令牌字段 const form = document.querySelector('form'); const csrfInput = document.createElement('input'); csrfInput.type = 'hidden'; csrfInput.name = 'csrfmiddlewaretoken'; csrfInput.value = csrfToken; form.appendChild(csrfInput); } }) .catch(err => console.log('获取CSRF令牌失败:', err)); });
方案二:给Django登录视图禁用CSRF校验(不推荐)
如果完全信任外部服务器,可以跳过该视图的CSRF校验,直接接收跨域表单提交:
自定义登录视图:
from django.contrib.auth.views import LoginView from django.views.decorators.csrf import csrf_exempt from django.utils.decorators import method_decorator @method_decorator(csrf_exempt, name='dispatch') class NoCsrfLoginView(LoginView): template_name = 'registration/login.html' # 保持原登录模板路径更新路由配置:
在urls.py中替换默认登录路由:from .views import NoCsrfLoginView urlpatterns = [ # ...其他路由 path('accounts/login/', NoCsrfLoginView.as_view(), name='login'), ]注意:此方法会关闭该视图的CSRF防护,存在被跨站伪造请求的风险,仅适合高度信任的场景。
方案三:改用DRF API实现登录(推荐)
通过Django REST Framework提供无CSRF校验的登录API,更适合跨域场景:
安装并配置DRF:
pip install djangorestframework djangorestframework-authtoken在
settings.py中添加:INSTALLED_APPS = [ # ...其他应用 'rest_framework', 'rest_framework.authtoken', ]运行迁移:
python manage.py migrate添加登录API路由:
from rest_framework.authtoken.views import obtain_auth_token urlpatterns = [ # ...其他路由 path('api/login/', obtain_auth_token, name='api_login'), ]外部页面通过JS提交到API:
const loginForm = document.querySelector('form'); loginForm.addEventListener('submit', function(e) { e.preventDefault(); const formData = new FormData(this); fetch('http://djangoserver.com/api/login/', { method: 'POST', body: formData }) .then(res => res.json()) .then(data => { if (data.token) { // 登录成功,可跳转到Django系统页面或存储token用于后续请求 window.location.href = 'http://djangoserver.com/'; } else { alert('用户名或密码错误'); } }) .catch(err => console.log('登录请求失败:', err)); });
内容的提问来源于stack exchange,提问作者whitebear
相关产品推荐
相关产品推荐

