为什么Django在Varnish代理后不生成CSRF或会话cookie?

7 投票
3 回答
2750 浏览
提问于 2025-04-16 18:00

我在一个运行着Django 1.2.5的Linux服务器上,用的是Apache2。出于某种原因,Django似乎无法存储CSRF或会话cookie。因此,当我尝试登录Django的管理后台时,提交登录表单后会出现CSRF验证错误。有没有人遇到过这个问题并找到了解决办法?

我在我的VPS(虚拟专用服务器)上尝试访问这个网址是可以正常发帖的,例子是:vps123.hostdomain.com/admin/,在这个域名下,cookie是可以正常设置的。但是,当我去www.sitedomain.com/admin/尝试登录时,就会出现CSRF 403错误,提示cookie不存在,而我在浏览器的cookie中也找不到。

我在设置文件中尝试过设置以下内容:

SESSION_COOKIE_DOMAIN = 'www.sitedomain.com'
CSRF_COOKIE_DOMAIN = 'www.sitedomain.com'

我还尝试过:

SESSION_COOKIE_DOMAIN = 'vps123.hostdomain.com'
CSRF_COOKIE_DOMAIN = 'vps123.hostdomain.com'

我在settings.py的MIDDLEWARE_CLASSES中添加了'django.middleware.csrf.CsrfViewMiddleware',而且表单中有CSRF令牌,并且在POST请求中也能看到。

我的cookie是启用的。我在多个浏览器和设备上都尝试过。

在www.sitedomain.com前面有一个Varnish代理服务器,我觉得这可能是问题的一部分。有使用过代理服务器和Django的人可能能对此提供一些帮助。

我的apache2配置:

NameVirtualHost *:80

<VirtualHost *:80>
    ServerName www.sitedomain.com
    ServerAlias www.sitedomain.com
    <Location "/">
        Options FollowSymLinks
        SetHandler python-program
        PythonInterpreter nzsite
        PythonHandler django.core.handlers.modpython
        PythonDebug On
        PythonPath "['/var/www/django_projects', '/var/www', '/usr/lib/python2.6/dist-packages'] + sys.path"
        SetEnv DJANGO_SETTINGS_MODULE project_one.settings
    </Location>
    <location "/phpmyadmin">
        SetHandler None
    </location>
</VirtualHost>

<VirtualHost *:80>
    ServerName othersite.sitedomain.com
    ServerAlias othersite.sitedomain.com
    <Location "/">
        Options FollowSymLinks
        SetHandler python-program
        PythonInterpreter ausite
        PythonHandler django.core.handlers.modpython
        PythonDebug On
        PythonPath "['/var/www/django_projects', '/var/www', '/usr/lib/python2.6/dist-packages'] + sys.path"
        SetEnv DJANGO_SETTINGS_MODULE project_two.settings
    </Location>
    <location "/phpmyadmin">
        SetHandler None
    </location>
</VirtualHost>

3 个回答

0

你有没有用csrf信息来更新你的模板数据?

from django.core.context_processors import csrf

def index(request)
    data = {"listitems": items}
    data.updates(csrf(request))

    return render_to_response('template.html', data)
2

你在表单模板里加上 {{csrf_token}} 了吗?

<form autocomplete="off" method="post" action="{% url auth_login %}">{% csrf_token %}
    {{form|as_p}}
    <input type='submit' />
</form>

还有,记得加上中间件吗?

    'django.middleware.csrf.CsrfViewMiddleware',

根据你编辑的内容,我猜这可能和Apache里的虚拟主机配置有关(如果你的服务商使用的是Apache的话)。下面是我一个Apache配置的修改版。

<VirtualHost *:80>
ServerName www.domain.com

WSGIProcessGroup my-django-site
WSGIScriptAlias / /path-to-my-django-site/wsgi/production.wsgi
Alias /media /path-to-my-django-site/media
</VirtualHost> 

可能需要注意的是,Apache里的服务器名称必须和你访问的域名一致,同时还要和你Django配置里的 *_COOKIE_DOMAIN 设置匹配。不过我不确定你是否能更改这些设置。如果其他方法都没用,建议你和服务商联系一下。

3

问题是我在网站前面有一个Varnish代理服务器。这个Varnish服务器会处理请求,并把请求中的cookies去掉。为了修复这个问题,我需要让管理Varnish服务器的公司把'/admin'加到一个例外列表里,这样cookies才能正常传递。抱歉,我无法详细解释Varnish的工作原理。

撰写回答