在Django 1.4.3中避免CSRF错误
我正在使用Django设计一个基本的登录和登出页面。下面是我的代码。
settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
...........
...........
"django.contrib.messages.context_processors.messages",
"django.core.context_processors.request",
"django.core.context_processors.csrf",
)
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)
INSTALLED_APPS = (
'django.contrib.auth',
.......
.......
)
urls.py
from django.conf.urls.defaults import *
from django.conf import settings
urlpatterns = patterns('',
url(r'^$', 'learn_django.views.home_page'),
url(r'^login/$', 'learn_django.views.login'),
url(r'^logged_in$', 'learn_django.views.logged_in'),
url(r'^logout/$', 'learn_django.views.logout'),
)
if settings.DEBUG:
urlpatterns = patterns('',
url(r'^media/(?P<path>.*)$', 'django.views.static.serve',{'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
) + urlpatterns
views.py
from django.shortcuts import render_to_response
from django.template import RequestContext
def home_page(request):
return render_to_response("home_page.html")
def login(request):
return render_to_response("login.html")
def logged_in(request):
return render_to_response("logged_in.html",context_instance=RequestContext(request))
base.html
{% load staticfiles %}
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="stylesheet" href="{% static 'css/home_remaining.css' %}" type="text/css">
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<header>
<div class='header_div'>
<div class="logout"><p id='logout'><a href="/logout" >Logout</a></p><div>
<div class="login"><p id='login'> <a href="/login" >Login</a></p><div>
</div>
</header>
<div class="body_content">
{% block body %}{% endblock %}
</div>
</body>
</html>
login.html
{% extends 'base.html' %}
{% block title %}Login Page{% endblock %}
{% block body %}
<div id='container'>
<form action="/logged_in" method="POST">
{% csrf_token %}
<label for="name">Username:</label><input type="name">
<label for="username">Password:</label><input type="password">
<div id="lower">
<input type="submit" value="Login">
</div>
</form>
</div>
{% endblock %}
上面的代码展示了一个登录表单,当我们点击base.html
中的登录
链接时,会显示这个表单。
在登录表单显示后,我输入了一些用户名
和密码
,然后点击了登录
按钮,结果出现了一个错误页面,提示csrf错误
。
我在网上查了很多资料,并在表单标签内添加了{% csrf_token %}
,还在settings.py
的模板上下文处理器中添加了django.core.context_processors.csrf
。
下面是错误信息的一部分:
Forbidden (403)
CSRF verification failed. Request aborted.
Help
Reason given for failure:
CSRF cookie not set.
In general, this can occur when there is a genuine Cross Site Request Forgery, or when Django's CSRF mechanism has not been used correctly. For POST forms, you need to ensure:
Your browser is accepting cookies.
The view function uses RequestContext for the template, instead of Context.
In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL.
If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as well as those that accept the POST data.
You're seeing the help section of this page because you have DEBUG = True in your Django settings file. Change that to False, and only the initial error message will be displayed.
You can customize this page using the CSRF_FAILURE_VIEW setting.
当我从模板上下文处理器中移除django.core.context_processors.csrf
后,程序正常工作了。但是我还是想使用csrf保护。
那么,以上的视图代码到底有什么问题,为什么会出现csrf错误页面?我该如何避免这个错误页面呢?
我是否需要在我的views.py
函数中添加任何代码?
有没有人能在我的函数中添加基本的登录和登出功能代码,这样我就能更好地理解代码的实际操作……
编辑
针对上述问题,我导入了csrf_exempt函数,像这样:
from django.views.decorators.csrf import csrf_exempt
然后在logged_in
视图前面加上这个装饰器,结果点击登录按钮时没有出现错误页面。
但我还是在想,为什么下面提到的方法,比如从模板发送Requestcontext,还是不管用呢?
1 个回答
你需要把一个 RequestContext
传给你的 render_to_response
函数。
def home_page(request):
return render_to_response("home_page.html", context_instance=RequestContext(request))
或者你可以使用新的渲染函数,它会帮你处理 RequestContext
的传递。
def home_page(request):
return render(request, "home_page.html")
RequestContext 会在传给模板的上下文字典中添加一些有用的信息,比如 csrf 令牌。想了解更多,可以看看 RequestContext 的文档。
在你的情况下,你的 login
视图正在渲染 login.html
模板,但没有传递 csrf 令牌。当 login.html
模板向服务器提交数据(到 /logged_in
)时,logged_in
视图会检查这个 csrf 令牌。结果发现没有这个令牌(因为你从来没有包含它),所以它认为这是一个跨站请求伪造。
可以看看 csrf 的文档,这样你会更明白这个过程。