Django 本地多域名访问管理后台如何解决 CSRF 403?
结论
通过不同域名访问 Django 时,浏览器会分别保存 Cookie。先确认 other_url.local 的管理后台页面是否设置了 CSRF Cookie,以及登录请求是否带回该 Cookie。若 Cookie 已发送,再检查 Django 的主机配置和 CSRF 来源配置。只设置 CSRF_COOKIE_SAMESITE 和 CSRF_COOKIE_SECURE,既不会让不同域名共享 Cookie,也不会自动信任新的请求来源。
你可以在 http://localhost:8000/ 登录,但从 http://other_url.local:8000/django-admin 提交登录表单时收到 CSRF cookie not set。这个报错通常表示请求中没有 CSRF Cookie。Django 拒绝不受信任的请求来源,则属于另一项检查。
检查主机和 CSRF 来源
确认开发设置允许这两个域名,并将实际使用的来源加入 CSRF_TRUSTED_ORIGINS。例如:
ALLOWED_HOSTS = [
"localhost",
"other_url.local",
]
CSRF_TRUSTED_ORIGINS = [
"http://localhost:8000",
"http://other_url.local:8000",
]
根据实际访问地址调整条目。较新版本的 Django 要求 CSRF_TRUSTED_ORIGINS 条目包含协议;如果使用较旧版本,请参照对应版本的设置格式。添加可信来源可以解决来源校验问题,但无法补上浏览器未保存或未发送的 Cookie。
如果项目使用 django-tenants,还需确认 other_url.local 已按项目配置登记为对应租户的域名,且请求路由到了预期租户。租户域名识别和 CSRF 校验需要分别检查。
检查 CSRF Cookie 是否设置并发送
打开浏览器开发者工具的 Network 面板,访问 http://other_url.local:8000/django-admin,检查响应是否设置了 csrftoken(或项目自定义的 CSRF Cookie 名称)。然后提交登录表单,查看请求的 Request Headers 中是否带有该 Cookie。
也可以按以下顺序排查:
- 确认浏览器地址栏始终使用同一个主机名。不要先从
localhost打开表单,再切换到other_url.local提交。 - 检查打开表单的响应是否设置了 CSRF Cookie。如果没有,确认 Django 的 CSRF 中间件已启用、响应经过了预期的中间件,并检查浏览器是否拒收 Cookie。
- 检查登录 POST 请求是否带回该 Cookie。如果没有,查看 Cookie 的 Domain、Path、SameSite、Secure 属性,并确认是否有扩展或浏览器策略阻止 Cookie。
- 清除该站点的旧 Cookie,再重新打开登录页尝试,排除旧 Cookie 或表单状态的干扰。
是否需要共享 Cookie 域
如果每个别名都单独打开页面并登录,通常无需共享 Cookie 域,浏览器会为各个主机分别保存 Cookie。如果确实需要让多个子域共享 Cookie,可以考虑设置 CSRF_COOKIE_DOMAIN,但这些主机必须属于同一个有效的可共享域名。例如,只有在主机确实是同一可共享父域的子域时,才适合将 Cookie 域设为该父域。别名都指向本机,并不代表它们属于可共享的 Cookie 域。.local 等本地域名的 Cookie 行为也应在实际浏览器中验证。
如果只是为了在本地测试多个租户,使用同一父域下的不同子域,并在租户路由配置中识别这些主机,通常更容易管理 Cookie 和域名设置。具体如何解析域名,取决于本地环境。
在 Django 配置中,CSRF_COOKIE_SAMESITE = None 表示不设置 SameSite 属性;CSRF_COOKIE_SECURE = False 允许 Cookie 通过 HTTP 发送。这两项不会使不同主机共享 Cookie。先在浏览器中确认 Cookie 是否设置并随请求发回,再决定是否调整域名或 Cookie 属性。
备注:内容仅供参考。
