Django生产环境仅登录时出现403 Forbidden(CSRF验证失败)问题
Django生产环境登录表单CSRF验证失败问题
问题现象
使用Django自带的Login/authentication登录认证功能,在生产环境提交登录POST请求时触发403 Forbidden错误,提示:
CSRF verification failed. Request aborted.
具体原因:CSRF cookie not set.
该问题仅出现在登录表单,应用内其他表单无异常;本地环境登录功能正常;生产环境中先访问admin再登录可正常使用,但关闭浏览器后重新登录又触发403错误。使用Django 3.2版本。
登录表单代码
{% extends "main/base.html" %} {% load static %} {% load widget_tweaks %} {% block content%} <div class='container'> <div class='row pt-4'> <div class="col"> </div> <div class="col-md-4 col-md-offset-4"> <div class="card text-center"> <!-- Login Form --> <div class="card-header bg-dark"> <h2 class="text-secondary">Login</h2> </div> <div class="card-body card text-left"> <form method="POST"> {% csrf_token %} {% for hidden in form.hidden_fields %} {{ hidden }} {% endfor %} {% for field in form.visible_fields %} <div class="form-group"> <label>{{ field.label_tag }}</label> {% render_field field class="form-control" %} {% for error in field.errors %} <span class="help-block">{{ error }}</span> {% endfor %} </div> {% endfor %} <div class="form-group"> <p>¿Olvidaste tú usuario o contraseña?<a href=""> Click aquí!</a></p> </div> <div class="form-group"> <button type="submit" class="btn btn-primary">Ingresar</button> </div> </form> </div> </div> </div> <div class="col"> </div> </div> </div> {% endblock %}
已尝试的Settings配置
ALLOWED_HOSTS = ['http://*', 'https://*'] # 也试过填写具体URL CSRF_TRUSTED_ORIGINS = ['http://*', 'https://*'] # 也试过填写具体URL CSRF_COOKIE_SECURE = True # 也试过设为False SESSION_COOKIE_SECURE = True # 也试过设为False
网络请求截图

解决方案
1. 配置CSRF Cookie的Domain属性
生产环境中,浏览器可能因为Cookie的Domain不匹配而拒绝保存CSRF Cookie。在settings.py中添加:
# 替换为你的生产域名,比如 example.com,不要加http/https前缀 CSRF_COOKIE_DOMAIN = "your-production-domain.com" # 如果是子域名场景,设置为 .your-production-domain.com(注意开头的点)
2. 确认登录视图使用官方认证视图
确保登录路由指向Django自带的LoginView,避免自定义视图未正确处理CSRF逻辑。urls.py示例:
from django.contrib.auth.views import LoginView urlpatterns = [ # ... path('login/', LoginView.as_view(template_name='你的登录模板路径'), name='login'), ]
3. 修复反向代理(如Nginx)的请求头传递
如果生产环境使用反向代理,需确保请求头正确传递给Django,否则Django无法识别正确的请求来源。以Nginx为例,在配置中添加:
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr;
同时在settings.py中启用相关配置:
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') USE_X_FORWARDED_HOST = True
4. 调整CSRF Cookie的SameSite属性
现代浏览器对Cookie的SameSite属性限制严格,在settings.py中设置合适的值:
# 常规场景用Lax即可 CSRF_COOKIE_SAMESITE = 'Lax' # 如果是跨域登录场景,设置为None,但必须配合CSRF_COOKIE_SECURE=True # CSRF_COOKIE_SAMESITE = 'None' # CSRF_COOKIE_SECURE = True
5. 清除浏览器缓存测试
旧的Cookie或缓存可能导致冲突,测试时使用浏览器隐私模式,或手动清除对应域名的Cookie和缓存后重试。
内容的提问来源于stack exchange,提问作者Jorge López
相关产品推荐
相关产品推荐

