为什么Django在Varnish代理后不生成CSRF或会话cookie?
我在一个运行着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 个回答
你有没有用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)
你在表单模板里加上 {{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 设置匹配。不过我不确定你是否能更改这些设置。如果其他方法都没用,建议你和服务商联系一下。
问题是我在网站前面有一个Varnish代理服务器。这个Varnish服务器会处理请求,并把请求中的cookies去掉。为了修复这个问题,我需要让管理Varnish服务器的公司把'/admin'加到一个例外列表里,这样cookies才能正常传递。抱歉,我无法详细解释Varnish的工作原理。