Метод POST всегда возвращает 403 Запрещено

Я прочитал Django - проверка CSRF не удалась и несколько вопросов (и ответов), связанных с методом django и POST. Один из ответов "лучший, но не работающий для меня" qaru.site/info/364619/...

Все утвержденные ответы предполагают как минимум 3 вещи:

  • Использовать RequestContext в качестве третьего параметра render_to_response_call
  • Добавить {% csrf_token%} в каждой форме с методом POST
  • Проверьте MIDDLEWARE_CLASSES в settings.py

Я сделал точно так, как предполагалось, но ошибка все же появилась. Я использую django 1.3.1 (из репозитория ubuntu 12.04) и python 2.7 (по умолчанию от ubuntu)

Это мой вид:

# Create your views here.
from django.template import RequestContext
from django.http import HttpResponse
from django.shortcuts import render_to_response
from models import BookModel

def index(request):
    return HttpResponse('Welcome to the library')

def search_form(request):
    return render_to_response('library/search_form.html')

def search(request):
    if request.method=='POST':
        if 'q' in request.POST:
            q=request.POST['q']
            bookModel = BookModel.objects.filter(title__icontains=q)
            result = {'books' : bookModel,}
            return render_to_response('library/search.html', result, context_instance=RequestContext(request))
        else:
            return search_form(request)
    else:
        return search_form(request)

и это мой шаблон (search_form.html):

{% extends "base.html" %}
{% block content %}
<form action="/library/search/" method="post">
    {% csrf_token %} 
    <input type="text" name="q">
    <input type="submit" value="Search">
</form>
{% endblock %}

Я перезапустил сервер, но 403 запрещенная ошибка все еще существует, сообщив, что проверка CSRF не удалась.

У меня есть 2 вопроса:

  • Как исправить эту ошибку?
  • Почему так сложно сделать "POST" в django, я имею в виду, есть ли какая-то конкретная причина сделать его настолько подробным (я пришел из PHP и никогда не обнаруживал такую ​​проблему раньше)?

Ответ 1

Попробуйте поместить RequestContext в представление search_form render_to_response:

context_instance=RequestContext(request)

Ответ 2

Возможно, я ошибался, но нашел эти решения довольно сложными.

то, что сработало для меня, просто включало мой токен csrf в мой почтовый запрос.

$.ajax({
    type: "POST",
    url: "/reports/",
    data: { csrfmiddlewaretoken: "{{ csrf_token }}",   // < here 
            state:"inactive" 
          },
    success: function() {
        alert("pocohuntus")
        console.log("prototype")
    }
})

Ответ 3

Самый простой способ избежать таких проблем - использовать render ярлык.

from django.shortcuts import render
# .. your other imports

def search_form(request):
    return render(request, 'library/search_form.html')

def search(request):
    q = request.GET.get('q')
    results = BookModel.objects.all()
    if q:
        results = results.filter(title__icontains=q)
    return render(request, 'library/search.html', {'result': results})

Ответ 4

Этот ответ предназначен для людей, которые могут столкнуться с этой же проблемой в будущем.

Тег шаблона CSRF {{csrf_token}}, который требуется для форм в Django, предотвращает запреты на кросс-сайты. CSRF позволяет злоумышленнику посещать клиентский браузер для запросов на ваш собственный сервер. Следовательно, csrf_token, предоставляемый django, упрощает защиту вашего сервера django и сайта от такого типа вредоносной атаки. Если ваша форма не защищена csrf_token, django возвращает 403 запретную страницу. Это форма защиты вашего сайта, особенно если токен не был упущен намеренно.

Но есть сценарии, в которых сайт django не захочет защищать свои формы с помощью csrf_token. Например, я разработал приложение USSD, и функция просмотра требуется для получения запроса POST из USSD API. Следует отметить, что запрос POST не был из формы на клиенте, поэтому риск CSRF невозможен, поскольку вредоносный сайт не может отправлять запросы. Запрос POST принимается, когда пользователь набирает код USSD, а не при отправке формы.

Другими словами, бывают ситуации, когда функция должна получить запрос POST, и не было бы необходимости {{csrf_token}}.

Django предоставляет нам декоратор @csrf_exempt. Этот декоратор отмечает вид как освобожденный от защиты, обеспечиваемой промежуточным программным обеспечением.

from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse

@csrf_exempt
def my_view(request):
    return HttpResponse('Hello world')

Django также предоставляет другой декоратор, который выполняет ту же функцию с {{csrf_token}}, но не отклоняет входящий запрос. Этот декоратор @requires_csrf_token. Например:

@requires_csrf_token
def my_view(request):
    c = {}
    # ...
    return render(request, "a_template.html", c)

Последний декоратор, который будет упомянут в этом сообщении, делает то же самое, что и {{csrf_token}}, и он называется @csrf_protect. Однако использование этого декоратора само по себе не является лучшей практикой, потому что вы можете забыть добавить его в свои представления. Например:

@csrf_protect
def my_view(request):
    c = {}
    # ...
    return render(request, "a_template.html", c)

Ниже приведены некоторые ссылки, которые помогут лучше объяснить и объяснить.

https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/#module-django.views.decorators.csrf

https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/

http://www.squarefree.com/securitytips/web-developers.html#CSRF

Ответ 5

Ответ составляет 403 бит,  django требует токена csrf (включенную в данные сообщения) в каждом запросе POST, который вы делаете.

Существуют различные способы сделать это, например:

Приобретение маркера из cookie и метода описано в статье введите ссылку здесь

или

Вы можете получить доступ к нему из DOM с помощью {{csrf_token}}, доступного в шаблоне

Итак, теперь, используя второй метод:

var post_data = {
  ...
  'csrfmiddlewaretoken':"{{ csrf_token }}"
  ...
}
$.ajax({
  url:'url',
  type:'POST'
  data:post_data,
  success:function(data){
    console.log(data);
  },
  error:function(error){
    console.log(error);
  }
});

Ответ 6

Вы также можете использовать

direct_to_template(request, 'library/search.html', result) 

вместо

render_to_response('library/search.html', result, context_instance=RequestContext(request))

потому что direct_to_template автоматически добавляет RequestContext. Но обратите внимание, что direct_to_template будет устаревать, а django предлагает вместо этого использовать CBV TemplateView.

RequestContext позволяет использовать контекстные процессоры. И это ваша ошибка: {% csrf_token %} выводит пустую строку, и вы получили 403.

Ответ 7

Вам нужно использовать RequestContext с ответом

например в view.py файле

from django.template import RequestContext

def home(request):
    return render_to_response('home.html',RequestContext(request, {}))