Метод POST всегда возвращает 403 Forbidden
я прочитала проверка Django - CSRF не удалась и несколько вопросов (и ответов), связанных с методом django и POST. Один из лучших-но-не-работающих-для-меня ответ https://stackoverflow.com/a/4707639/755319
все утвержденные ответы предполагают, по крайней мере, 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 вопроса:
- как исправить эту ошибку?
- почему так сложно сделать "сообщение" в django, я имею в виду, есть ли какая-то конкретная причина сделать его таким подробным (я пришел из PHP и никогда не находил такой проблемы раньше)?
7 ответов
Попробуйте поместить RequestContext в представление search_form render_to_response:
context_instance=RequestContext(request)
Я, возможно, ошибаюсь, однако я нашел вышеуказанные решения довольно сложными.
то, что работало для меня, просто включало мой токен csrf в мой запрос post.
$.ajax({
type: "POST",
url: "/reports/",
data: { csrfmiddlewaretoken: "{{ csrf_token }}", // < here
state:"inactive"
},
success: function() {
alert("pocohuntus")
console.log("prototype")
}
})
самый простой способ избежать подобных проблем-использовать 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})
ответ 403 bcoz, django требует токена csrf (включенного в данные post) в каждом запросе 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);
}
});
это ответ для людей, которые могут столкнуться с этой же проблемой в будущем.
CSRF-атаку {{csrf_token}}
шаблон тег, который требуется для форм в Django предотвратить подделки запроса на перекрестном сайте. CSRF позволяет вредоносному сайту, который был посещен браузером клиента, делать запросы на ваш собственный сервер. Следовательно, csrf_token, предоставляемый django, упрощает защиту вашего сервера и сайта django от этого типа вредоносной атаки. Если ваш форма не защищена csrf_token, django возвращает 403 запрещенную страницу. Это форма защиты для вашего сайта, особенно когда токен не был оставлен намеренно.
но есть сценарии, где сайт django не хотел бы защищать свои формы с помощью csrf_token. Например, я разработал приложение USSD, и для получения запроса POST из USSD API требуется функция view. Следует отметить, что запрос 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
вы также можете использовать
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 %}
outputed пустая строка, и вы получили 403.
вам нужно использовать RequestContext
ответ
например в
from django.template import RequestContext
def home(request):
return render_to_response('home.html',RequestContext(request, {}))