django种表单post出现CSRF verification failed( CSRF验证失败 ) 的两种解决方式

现象

表单界面例如以下:


在点击提交之后,出现例如以下错误页面:



HTML的代码例如以下:

contact_form.html

<!DOCTYPE HTML PUBLIC >

<html>
<head>
    <title>Contact us</title>
</head>

<body>
    <h1>Contact us</h1>
    {% if errors %}
       <ul>
          {% for error in errors %}
           <li>{{ error }}</li>
           {% endfor %}
       </ul>
    {% endif %}
    <form action="/contact/" method="post">
        <p>Subject: <input type="text" name="subject" value="{{ subject }}"></p>
        <p>Your e-mail (optional): <input type="text" name="email" value="{{ email }}"></p>
        <p>Message: <textarea name="message" rows="10" cols="50">{{ message }}</textarea></p>
        <input type="submit" value="Submit">
    </form>
</body>
</html>

view代码例如以下:

view.py

# -*- coding: utf-8 -*-

from django.core.mail import send_mail
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response

def contact(request):
    errors = []
    if request.method == 'POST':
        if not request.POST.get('subject', ''):
            errors.append('Enter a subject.')
        if not request.POST.get('message', ''):
            errors.append('Enter a message.')
        if request.POST.get('email') and '@' not in request.POST['email']:
            errors.append('Enter a valid e‐mail address.')
        if not errors:
            send_mail(
                      request.POST['subject'],
                      request.POST['message'],
                      request.POST.get('email', 'noreply@example.com'),
                      ['siteowner@example.com'],
                      )
            return HttpResponseRedirect('/contact/thanks/')
    return render_to_response('contact_form.html', {
                                                    'errors': errors,
                                                    'subject': request.POST.get('subject', ''),
                                                    'message': request.POST.get('message', ''),
                                                    'email': request.POST.get('email', ''),
                                                    })

一般浏览器都是开启了cookies的,所以在上面图中的错误信息中。我们主要关注后三点,依据提示进行更改:

解决方式一:CSRF验证设置

1. 在 view.py 中的 render_to_response 中,使用 RequestContext 来取代默认的 Context 。

view.py

# -*- coding: utf-8 -*-

from django.core.mail import send_mail
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import RequestContext

def contact(request):
    errors = []
    if request.method == 'POST':
        if not request.POST.get('subject', ''):
            errors.append('Enter a subject.')
        if not request.POST.get('message', ''):
            errors.append('Enter a message.')
        if request.POST.get('email') and '@' not in request.POST['email']:
            errors.append('Enter a valid e‐mail address.')
        if not errors:
            send_mail(
                      request.POST['subject'],
                      request.POST['message'],
                      request.POST.get('email', 'noreply@example.com'),
                      ['siteowner@example.com'],
                      )
            return HttpResponseRedirect('/contact/thanks/')
    return render_to_response('contact_form.html', {
                                                    'errors': errors,
                                                    'subject': request.POST.get('subject', ''),
                                                    'message': request.POST.get('message', ''),
                                                    'email': request.POST.get('email', ''),
                                                    },context_instance=RequestContext(request))

2. 在模板文件里的 form 表单内加入 {% csrf_token %} 。

contact_form.html

<!DOCTYPE HTML PUBLIC >

<html>
<head>
    <title>Contact us</title>
</head>

<body>
    <h1>Contact us</h1>
    {% if errors %}
       <ul>
          {% for error in errors %}
           <li>{{ error }}</li>
           {% endfor %}
       </ul>
    {% endif %}
    <form action="/contact/" method="post">
        <br />{% csrf_token %}<br />
        <p>Subject: <input type="text" name="subject" value="{{ subject }}"></p>
        <p>Your e-mail (optional): <input type="text" name="email" value="{{ email }}"></p>
        <p>Message: <textarea name="message" rows="10" cols="50">{{ message }}</textarea></p>
        <input type="submit" value="Submit">
    </form>
</body>
</html>

測试执行,成功!

PS:上文中图片中的错误信息第四条,在建立djangoproject的时候 setting.py 已经自己主动加入了 'django.middleware.csrf.CsrfViewMiddleware',

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.middleware.locale.LocaleMiddleware',
)



解决方式二:不使用 CSRF 验证

1. 在 setting.py 文件里删除  'django.middleware.csrf.CsrfViewMiddleware', ,例如以下所看到的

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    #'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.middleware.locale.LocaleMiddleware',
)

2. 移除 form 表单中的  {% csrf_token %} 标记。例如以下所看到的:

contact_form.html

<!DOCTYPE HTML PUBLIC >

<html>
<head>
    <title>Contact us</title>
</head>

<body>
    <h1>Contact us</h1>
    {% if errors %}
       <ul>
          {% for error in errors %}
           <li>{{ error }}</li>
           {% endfor %}
       </ul>
    {% endif %}
    <form action="/contact/" method="post">
        <p>Subject: <input type="text" name="subject" value="{{ subject }}"></p>
        <p>Your e-mail (optional): <input type="text" name="email" value="{{ email }}"></p>
        <p>Message: <textarea name="message" rows="10" cols="50">{{ message }}</textarea></p>
        <input type="submit" value="Submit">
    </form>
</body>
</html>

3. 在 view.py 中的 render_to_response 中,不使用 RequestContext 。例如以下所看到的:

view.py

# -*- coding: utf-8 -*-

from django.core.mail import send_mail
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import RequestContext

def contact(request):
    errors = []
    if request.method == 'POST':
        if not request.POST.get('subject', ''):
            errors.append('Enter a subject.')
        if not request.POST.get('message', ''):
            errors.append('Enter a message.')
        if request.POST.get('email') and '@' not in request.POST['email']:
            errors.append('Enter a valid e‐mail address.')
        if not errors:
            send_mail(
                      request.POST['subject'],
                      request.POST['message'],
                      request.POST.get('email', 'noreply@example.com'),
                      ['siteowner@example.com'],
                      )
            return HttpResponseRedirect('/contact/thanks/')
    return render_to_response('contact_form.html', {
                                                    'errors': errors,
                                                    'subject': request.POST.get('subject', ''),
                                                    'message': request.POST.get('message', ''),
                                                    'email': request.POST.get('email', ''),
                                                    })

又一次执行,測试成功!




posted @ 2016-03-29 08:39  phlsheji  阅读(4188)  评论(0编辑  收藏  举报