web-dev-qa-db-ja.com

Djangoフレームワークでajax Postリクエストを行うときの403 Forbiddenエラー

Django=フレームワークで作成しているWebアプリケーションにjqueryを統合しようとしています。ただし、単純なajax呼び出しを実行しようとすると、苦労しています。テンプレートajax呼び出しを処理するためのフォームhtmlおよびjavascriptを含むファイルは次のようになります。

<script type="text/javascript">
$(document).ready(function() {
$( "#target" ).submit(function() {
console.log('Form was submitted');
$.ajax({
        type: "POST",
        url: "/hello/",  // or just url: "/my-url/path/"
        data: {
            query: $( "#query" ).val()   
        },
        success: function(data) {
            console.log(data);
        }
    });
return false;
  });   
  })
</script>
<form id="target" action="." method="post">{% csrf_token %}
 <input id= "query" type="text" value="Hello there">
 <input type="submit" value="Search Recent Tweets">
</form>

Ajax呼び出しを処理することになっている私のviews.pyは次のようになります。

 from Django.core.context_processors import csrf
 from Django.shortcuts import render_to_response
 from Django.template.loader import get_template
 from Django.template import Context,RequestContext
 from Django.views.decorators.csrf import ensure_csrf_cookie
 from Django.http import HttpResponse

 # access resource
 def hello(request):
  c = {}
  c.update(csrf(request))
  if request.is_ajax():
        t = get_template('template.html')
        #html = t.render(Context({'result': 'hello world'}))
        con = RequestContext(request, {'result': 'hello world'})
        return render_to_response('template.html', c, con)
  else:
        return HttpResponse('Not working!') 

Cross-Site Request Forgery Protection の公式ドキュメントを追うことを試みましたが、同様の問題に対処するstackoverflowの質問もいくつか見ました。 htmlテンプレートファイルに{% csrf_token %}を含めましたが、まだ機能していないようです。コンソールにajax呼び出しが失敗したことを示すエラーが表示されます。

POST http://127.0.0.1:8000/hello/ 403 (FORBIDDEN)   

result変数をhttp応答とともに渡し、ajax呼び出しをスムーズに動作させるにはどうすればよいですか?どんな助けも大歓迎です。

Edit-1

おそらく、投稿リクエストとともにcsrfトークンを渡すことはありませんでした。 SOドキュメントに従って、テンプレートjavascriptに次のコードを追加しました。

function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
    var cookies = document.cookie.split(';');
    for (var i = 0; i < cookies.length; i++) {
        var cookie = jQuery.trim(cookies[i]);
        // Does this cookie string begin with the name we want?
        if (cookie.substring(0, name.length + 1) == (name + '=')) {
            cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
            break;
        }
    }
}
    return cookieValue;
}
var csrftoken = getCookie('csrftoken');
console.log(csrftoken);

//Ajax call
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
    crossDomain: false, // obviates need for sameOrigin test
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type)) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

ブラウザーでテンプレートhtmlページを更新すると、コンソールにnullが表示され、Cookieが設定されていないか定義されていないことが示唆されます。私は何が欠けていますか?

33
Annihilator8080

csrfmiddlewaretokenを投稿しなかったため、Django禁止します。 このドキュメント できます助けます。

42
Yohn

怠け者の場合:

最初のCookieのダウンロード: http://plugins.jquery.com/cookie/

HTMLに追加します。

<script src="{% static 'designer/js/jquery.cookie.js' %}"></script>

これで、有効なPOSTリクエストを作成できます:

var csrftoken = $.cookie('csrftoken');

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

$.ajax(save_url, {
    type : 'POST',
    contentType : 'application/json',
    data : JSON.stringify(canvas),
    success: function () {
        alert("Saved!");
    }

})
22
fivef

以前の回答はすべてその場で見つけましたが、状況を把握しましょう。

403の禁止された応答は、CSRFミドルウェアからのものです( Cross Site Request Forgery protection を参照):

デフォルトでは、着信リクエストがCsrfViewMiddlewareによって実行されるチェックに失敗すると、「403 Forbidden」応答がユーザーに送信されます。

多くのオプションが利用可能です。 jQueryにX-CSRFTokenを伴うすべてのAJAX=リクエストの前に$.ajaxSetupヘッダーを追加させるには、 @ fivefの答え に従うことをお勧めします。

この回答には、cookie jQueryプラグインが必要です。これが望ましくない場合、別の可能性は追加することです:

function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie != '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
var csrftoken = getCookie('csrftoken');

しかし: CSRF_COOKIE_HTTPONLY 設定がTrueに設定されている場合、 セキュリティミドルウェア が推奨するように頻繁に発生するため、@ensure_csrf_cookie()が使用されます。この場合、{% csrf_token %}をすべてのフォームで提供する必要があり、<input name="csrfmiddlewaretoken" value="cr6O9...FUXf6" type="hidden">などの出力が生成されます。そのため、csrfToken変数は次のようにして簡単に取得できます。

var csrftoken = $('input[name="csrfmiddlewaretoken"]').val();

もちろん、$.ajaxSetupはもちろん必要です。

利用可能な他のオプションは推奨されませんは、@csrf_exempt()で特定のフォームのミドルウェアまたはcsrf保護を無効にすることです。

5
Wtower

テンプレートにjsを埋め込まない場合の最速のソリューションは次のとおりです。

<script type="text/javascript"> window.CSRF_TOKEN = "{{ csrf_token }}"; </script>テンプレート内のscript.jsファイルへの参照の前に、csrfmiddlewaretokendata辞書に追加します。

$.ajax({
            type: 'POST',
            url: somepathname + "do_it/",
            data: {csrfmiddlewaretoken: window.CSRF_TOKEN},
            success: function() {
                console.log("Success!");
            }
        })

Jsをテンプレートに埋め込む場合、次のように簡単です:data: {csrfmiddlewaretoken: '{{ csrf_token }}'}

3
Marek Židek

Cookieを設定するには、 ensure_csrf_cookie ビューのデコレータ:

from Django.views.decorators.csrf import ensure_csrf_cookie

@ensure_csrf_cookie
def hello(request):
    code_here()
2
kelvinss

フォームが表示されているページ/ビューをキャッシュしていないことを確認してください。 CSRF_TOKENをキャッシュしている可能性があります。私に起こりました!

1
teewuane
data: {"csrfmiddlewaretoken" : "{{csrf_token}}"}

「csrfmiddlewaretoken」パラメーターを送信しないため、「403(FORBIDDEN)」が表示されます。テンプレートでは、各フォームに{%csrf_token%}があります。 「csrfmiddlewaretoken」をajaxデータ辞書に追加する必要があります。私の例では、「product_code」と「csrfmiddlewaretoken」をアプリ「basket」ビュー「remove」に送信しています。

$(function(){
    $('.card-body').on('click',function(){
        $.ajax({
          type: "post",
          url: "{% url 'basket:remove'%}",
          data: {"product_code": "07316", "csrfmiddlewaretoken" : "{{csrf_token}}" }
        });
    })
});
1
AndrewPt

このデコレータをディスパッチコードに含めてみてください

from Django.utils.decorators import method_decorator
from Django.views.decorators.csrf import csrf_exempt     
@method_decorator(csrf_exempt, name='dispatch')
def dispatch(self, request, *args, **kwargs):
     return super(LessonUploadWorkView,self).dispatch(request,*args,**kwargs)
1
mullerivan

SSL/httpsおよびCSRF_COOKIE_HTTPONLY = Falseの場合、 Django Doc で提案されているgetCookie(name)関数を使用するか、またはjquery.cookie.jsfivef によって提案されました。

Wtower summaryは完璧で、settings.pyからCSRF_COOKIE_HTTPONLYを削除した後でも機能すると思いましたが、httpsでは機能しません!

csrftokenがdocument.cookieに表示されない理由???

取得する代わりに

「Django_language = fr; csrftoken = rDrGI5cp98MnooPIsygWIF76vuYTkDIt」

しか得られない

「Django_language = fr」

どうして? SSL/httpsのようにheaders からX-CSRFTokenを削除します。これはNginxのプロキシヘッダーパラメーターによるものと思われますが、明らかにそうではありません。

Django doc Notes とは異なり、httpsでcookie内のcsrf_tokenを操作することは不可能のようです。 csrftokenを渡す唯一の方法は、HTMLで{%csrf_token%}を使用してDOMを介し、jQueryで取得することです。

var csrftoken = $('input[name="csrfmiddlewaretoken"]').val();

その後、ヘッダー( xhr.setRequestHeader )または params によってajaxに渡すことができます。

0
openHBP