You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django 4.2语言切换POST请求含CSRF仍返回403 Forbidden问题

Django 4.2 i18n语言切换首次请求403 Forbidden问题

问题现象

在基于Django 4.2的网站中使用i18n库实现语言切换功能,已在根urls.py配置相关路由,并在模板中编写了包含{% csrf_token %}的语言切换表单,但首次执行切换操作时返回403 Forbidden错误,服务器日志提示:

Forbidden (CSRF cookie not set.): /i18n/setlang/

首次触发403后再次切换可成功,私有窗口也存在相同现象:请求头中可见csrftoken,但首次切换时无lang cookie,成功后该cookie出现。

相关配置代码

urls.py配置

urlpatterns = [
    path('i18n/', include('django.conf.urls.i18n')),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

urlpatterns += i18n_patterns(
    path('',apiView.WebsiteHomepageTemplate.as_view(),name="url_homepage_template"),
)

模板表单代码

<ul class="dropdown-menu" role="menu" id="language-list">
  <li class="" id="language-switcher">
    <form action="{% url 'set_language' %}" method="post" name="lang_form">
      {% csrf_token %}
      <input name="next" type="hidden" value="/" />

      <select class="selectpicker" id="select_pickr" name="language">
        {% get_available_languages as LANGUAGES %}
        {% get_language_info_list for LANGUAGES as languages %}
        {% for language in languages %}

        <option value="{{ language.code }}" {% if language.code == LANGUAGE_CODE %} selected="selected" 
        {%endif %} data-content='{{ language.code }}}'>
          {% if language.code == 'en' %}
          English
          {% else %}
          हिंदी
          {% endif %}

        </option>

        {% endfor %}
      </select>
    </form>
  </li>
</ul>

安全配置

DEBUG = False
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.middleware.locale.LocaleMiddleware',# for multi language 
    'django.contrib.sessions.middleware.SessionMiddleware',
    # ...caching
    'django.middleware.cache.UpdateCacheMiddleware',   
    'corsheaders.middleware.CorsMiddleware', # new   
    'django.middleware.common.CommonMiddleware',  
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    # ...caching
    # 'django.middleware.cache.FetchFromCacheMiddleware',      
    'csp.middleware.CSPMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'debug_toolbar.middleware.DebugToolbarMiddleware',  
    'silk.middleware.SilkyMiddleware',  
    'axes.middleware.AxesMiddleware',    
]


AUTHENTICATION_BACKENDS = [
    # AxesStandaloneBackend should be the first backend in the AUTHENTICATION_BACKENDS list.
    'axes.backends.AxesStandaloneBackend',

    # Django ModelBackend is the default authentication backend.
    'django.contrib.auth.backends.ModelBackend',
]



X_FRAME_OPTIONS = 'DENY'
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_HSTS_SECONDS = 86400
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
CSRF_TRUSTED_ORIGINS = ['https://*.mywebsite.com']
SECURE_BROWSER_XSS_FILTER = True
SESSION_COOKIE_HTTPONLY = True





CSP_DEFAULT_SRC = ("'self'","mywebsite.com","ajax.googleapis.com" )
CSP_SCRIPT_SRC = (
    "'self'",
    "https://www.googletagmanager.com",
    "fonts.googleapis.com",
    "mywebsite.com",
    'https://www.google.com/recaptcha/',
    'https://www.gstatic.com/recaptcha/',
    'https://www.youtube.com/embed/',
    'https://cdnjs.cloudflare.com/ajax/libs/tiny-slider/2.9.2/min/tiny-slider.js',
    "https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js",
    # "'strict-dynamic'"
    # "'unsafe-inline'"
)
CSP_FONT_SRC = ("'self'", "fonts.googleapis.com","fonts.gstatic.com")    
CSP_STYLE_SRC = [
    "'self'",
    "mywebsite.com",
    "fonts.googleapis.com",
    "'unsafe-inline'"

]  
CSP_IMG_SRC = ("'self'",'mywebsite.com','data:','blob:')
CSP_FRAME_SRC =(
    "'self'", 
    'https://www.google.com/recaptcha/', 
    'https://recaptcha.google.com/recaptcha/',
    'https://www.youtube.com/',
    "https://www.google.com/maps/"
) 
CORS_ALLOWED_ORIGINS = [
    "https://mywebsite.com" ,
]

#CONTENT SECURITY POLICY
CSP_CONNECT_SRC =("'self'","https://www.google-analytics.com/")
# CSP_OBJECT_SRC = ("'self'", 'mywebsite.com')
CSP_BASE_URI = ("'self'", )
CSP_FRAME_ANCESTORS = ("'self'","https://www.google.com/" )
CSP_FORM_ACTION = ("'self'", )
CSP_MANIFEST_SRC = ("'self'", )
CSP_WORKER_SRC = ("'self'", )
CSP_MEDIA_SRC = ("'self'", )
CSP_CHILD_SRC = ("'self'", )    
CSP_FORM_ACTION = ("'self'","mywebsite.com")
# CSP_STYLE_SRC = ("'self'","mywebsite.com",)
CSP_INCLUDE_NONCE_IN = [
    'default-src',
    'script-src',
    # 'style-src',
]
CSP_OBJECT_SRC = ("'self'","mywebsite.com")     

解决方案

1. 修正中间件顺序

LocaleMiddleware的位置是核心问题,Django官方要求它必须放在SessionMiddleware之后、CommonMiddleware之前。当前配置中LocaleMiddleware在SessionMiddleware之前,会导致首次请求时session未初始化,无法正确生成并关联CSRF和语言cookie。修改后的中间件顺序:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',  # 调整到SessionMiddleware之后
    'django.middleware.cache.UpdateCacheMiddleware',   
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',  
    'django.middleware.csrf.CsrfViewMiddleware',
    # ...其余中间件保持不变
]

2. 主动触发CSRF Cookie设置

首次请求时,即使模板包含{% csrf_token %},也可能因缓存或CSP限制导致CSRF cookie未及时写入。可以通过两种方式解决:

  • 前端方式:在页面底部添加JS,页面加载时主动触发HEAD请求,强制设置CSRF cookie(需确保CSP允许内联脚本,或添加对应nonce):
document.addEventListener('DOMContentLoaded', () => {
    fetch(window.location.href, { method: 'HEAD', credentials: 'include' });
});
  • 后端方式:在首页视图中主动生成CSRF token,确保cookie在首次请求时被设置:
from django.middleware.csrf import get_token
from django.views.generic import TemplateView

class WebsiteHomepageTemplate(TemplateView):
    def get(self, request, *args, **kwargs):
        get_token(request)  # 主动生成CSRF token并设置cookie
        return super().get(request, *args, **kwargs)

3. 验证HTTPS环境下的Cookie设置

由于网站使用HTTPS,需确保session和CSRF cookie仅通过HTTPS传输,添加以下配置:

SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

4. 检查CSP对表单提交的影响

确认CSP_FORM_ACTION包含/i18n/setlang/的来源,当前配置("'self'","mywebsite.com")已满足,但如果使用JS提交表单,需确保CSP_SCRIPT_SRC允许对应的脚本执行。

内容的提问来源于stack exchange,提问作者Abhi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 14:57:00