AJAX投稿を介して、DjangoのCSRF保護メカニズムに準拠するいくつかのヘルプを使用できます。私はここの指示に従いました:
http://docs.djangoproject.com/en/dev/ref/contrib/csrf/
そのページにあるAJAXサンプルコードを正確にコピーしました。
http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax
xhr.setRequestHeader
呼び出しの前にgetCookie('csrftoken')
の内容を出力するアラートを配置すると、実際にいくつかのデータが取り込まれます。トークンが正しいことを確認する方法がわかりませんが、何かを見つけて送信することをお勧めします。
しかし、DjangoはまだAJAX投稿を拒否しています。
これが私のJavaScriptです。
$.post("/memorize/", data, function (result) {
if (result != "failure") {
get_random_card();
}
else {
alert("Failed to save card data.");
}
});
Djangoで表示されるエラーは次のとおりです。
[23/Feb/2011 22:08:29] "POST/memorize/HTTP/1.1" 403 2332
私は何かを逃していると確信しており、おそらくそれは簡単ですが、それが何であるかはわかりません。 SOを検索して、csrf_exempt
デコレータを介してCSRFチェックをオフにすることに関する情報を見ましたが、それは魅力的ではありません。私はそれを試してみましたが、うまくいきますが、POSTが、可能であればDjangoがそれを期待するように設計された方法で動作するようにします。
それが役に立つ場合に備えて、ここに私の見解がしていることの要点があります:
def myview(request):
profile = request.user.profile
if request.method == 'POST':
"""
Process the post...
"""
return HttpResponseRedirect('/memorize/')
else: # request.method == 'GET'
ajax = request.GET.has_key('ajax')
"""
Some irrelevent code...
"""
if ajax:
response = HttpResponse()
profile.get_stack_json(response)
return response
else:
"""
Get data to send along with the content of the page.
"""
return render_to_response('memorize/memorize.html',
""" My data """
context_instance=RequestContext(request))
返信いただきありがとうございます!
実際のソリューション
わかりました、私はなんとか問題を追跡しました。これは、Javascript(以下で提案する)コードにあります。
必要なのはこれです:
$.ajaxSetup({
beforeSend: function(xhr, settings) {
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;
}
if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
// Only send the token to relative URLs i.e. locally.
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
公式ドキュメントに投稿されたコードの代わりに: https://docs.djangoproject.com/en/2.2/ref/csrf/
動作するコードは、このDjangoエントリから来ています: http://www.djangoproject.com/weblog/2011/feb/08/security/
したがって、一般的な解決策は、「ajaxSendハンドラーの代わりにajaxSetupハンドラーを使用する」です。なぜ機能するのか分かりません。しかし、それは私にとってはうまくいきます:)
前の投稿(回答なし)
実際に同じ問題が発生しています。
Django 1.2.5に更新した後に発生します-AJAX 1.2.4でPOST Djangoリクエストにエラーはありませんでした(AJAXは保護されていませんが、うまくいきました)。
OPと同様に、Djangoのドキュメントに掲載されているJavaScriptスニペットを試しました。 jQuery 1.5を使用しています。また、「Django.middleware.csrf.CsrfViewMiddleware」ミドルウェアも使用しています。
私はミドルウェアのコードを追跡しようとしましたが、これで失敗することを知っています:
request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '')
その後
if request_csrf_token != csrf_token:
return self._reject(request, REASON_BAD_TOKEN)
「request_csrf_token」が空であるため、この「if」は真です。
基本的には、ヘッダーが設定されていないことを意味します。したがって、このJS行には何か問題があります。
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
?
提供された詳細が問題の解決に役立つことを願っています:)
$.ajax
関数を使用する場合は、データ本体にcsrf
トークンを追加するだけです。
$.ajax({
data: {
somedata: 'somedata',
moredata: 'moredata',
csrfmiddlewaretoken: '{{ csrf_token }}'
},
次の行をjQueryコードに追加します。
$.ajaxSetup({
data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
});
完了しました。
この問題は、DjangoがCookieからの値がフォームデータの一部として返されることを期待しているためです。前の回答のコードは、JavaScript値を取得してCookie値を探し出し、それをフォームデータに入れています。それは技術的な観点からそれを行う素敵な方法ですが、少し冗長に見えます。
過去には、JavaScript値を取得してトークン値を投稿データに入れることで、より簡単にそれを行ってきました。
テンプレートで{%csrf_token%}を使用すると、値を保持する非表示のフォームフィールドが出力されます。ただし、{{csrf_token}}を使用する場合は、トークンの裸の値を取得するだけなので、このようにjavascriptで使用できます。..
csrf_token = "{{ csrf_token }}";
その後、必要なキー名をハッシュに含めて、データとしてajax呼び出しに送信できます。
{% csrf_token %}
は、<form></form>
内にHTMLテンプレートを配置します
次のようなものに変換されます。
<input type='hidden' name='csrfmiddlewaretoken' value='Sdgrw2HfynbFgPcZ5sjaoAI5zsMZ4wZR' />
次のようにJSで単にgrepしないでください:
token = $("#change_password-form").find('input[name=csrfmiddlewaretoken]').val()
そして、それを渡す、例えば、いくつかのPOSTをする:
$.post( "/panel/change_password/", {foo: bar, csrfmiddlewaretoken: token}, function(data){
console.log(data);
});
フォームがJSなしでDjangoに正しく投稿された場合、csrfトークンをハッキングまたは乱雑に渡すことなく、ajaxを使用してフォームを段階的に拡張できるはずです。フォーム全体をシリアル化するだけで、すべてのフォームフィールドが自動的に取得されますを含む非表示のcsrfフィールド:
$('#myForm').submit(function(){
var action = $(this).attr('action');
var that = $(this);
$.ajax({
url: action,
type: 'POST',
data: that.serialize()
,success: function(data){
console.log('Success!');
}
});
return false;
});
これをDjango 1.3+およびjQuery 1.5+でテストしました。明らかに、これはDjangoアプリだけでなく、どのHTMLフォームでも機能します。
非jqueryの答え:
var csrfcookie = function() {
var cookieValue = null,
name = 'csrftoken';
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
};
使用法:
var request = new XMLHttpRequest();
request.open('POST', url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.setRequestHeader('X-CSRFToken', csrfcookie());
request.onload = callback;
request.send(data);
受け入れられた答えは、おそらくニシンです。 Django 1.2.4と1.2.5の違いは、AJAXリクエストのCSRFトークンの要件でした。
Django 1.3でこの問題に遭遇しましたが、そもそもCSRF Cookieが設定されていないことが原因ですでした。 Djangoは、必要でない限りcookieを設定しません。そのため、Django 1.2.4で実行されている排他的または重度のajaxサイトは、潜在的にクライアントにトークンを送信することはなく、トークンを必要とするアップグレードによって403エラーが発生します。
理想的な修正はこちらです: http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#page-uses-ajax-without-any-html-form
ただし、これがコードに追いついているだけのドキュメントでない限り、1.4を待つ必要があります。
Edit
また、後のDjangoのドキュメントではjQuery 1.5のバグに注意しているので、Djangoの推奨コードで1.5.1以降を使用していることを確認してください。 http:// docs .djangoproject.com/en/1.3/ref/contrib/csrf /#ajax
FirebugでFirefoxを使用します。 ajaxリクエストの実行中に「コンソール」タブを開きます。 DEBUG=True
を使用すると、応答としてNice Djangoエラーページが表示され、コンソールタブでajax応答のレンダリングされたhtmlを確認することもできます。
その後、エラーが何であるかがわかります。
X-CSRFToken
ヘッダーと{{ csrf_token }}
を使用してこれを純粋なJSで行う方法について誰も言及していないようです。そのため、CookieまたはDOMを検索する必要のない簡単なソリューションを次に示します。
var xhttp = new XMLHttpRequest();
xhttp.open("POST", url, true);
xhttp.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
xhttp.send();
このjsをhtmlファイルに貼り付けることができます。他のjs関数の前に置いてください
<script>
// using 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;
}
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$(document).ready(function() {
var csrftoken = getCookie('csrftoken');
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
});
</script>
ちょっと違うが似たような状況に出会ったばかりです。それがあなたのケースの解決策であるかどうか100%はわかりませんが、Djangoパラメータ 'csrfmiddlewaretoken'を適切なCookie値文字列で設定することにより、POST 1.3の問題を解決しました通常は、Djangoのテンプレートシステムによって '{%csrf_token%}'タグを使用してホームHTMLの形式で返されます。私は古いDjangoを試さず、Django1.3で問題を解決しました。私の問題は、フォームからAjaxを介して送信された最初のリクエストが正常に実行されたが、ヘッダー「X-CSRFToken」がCSRFトークン値とともに正しく配置されていても、まったく同じからの2回目の試行が失敗したことです最初の試行の場合のように。お役に立てれば。
よろしく、
ヒロ
誰かがこの仕事をするためにaxiosで苦労しているなら、これは私を助けました:
import axios from 'axios';
axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = 'X-CSRFToken'
ソース: https://cbuelter.wordpress.com/2017/04/10/Django-csrf-with-axios/
1)Django csrfチェック(送信する場合)は here
2)私の場合、settings.CSRF_HEADER_NAME
が 'HTTP_X_CSRFTOKEN'に設定され、AJAX呼び出しが 'HTTP_X_CSRF_TOKEN'という名前のヘッダーを送信していたため、機能していませんでした。 AJAX呼び出しで変更するか、Django設定で変更できます。
3)サーバー側で変更することを選択した場合、Djangoのインストール場所を見つけ、virtualenv
を使用しているcsrf middleware
.. fにブレークポイントをスローすると、次のようになります:~/.envs/my-project/lib/python2.7/site-packages/Django/middleware/csrf.py
import ipdb; ipdb.set_trace() # breakpoint!!
if request_csrf_token == "":
# Fall back to X-CSRFToken, to make things easier for AJAX,
# and possible for PUT/DELETE.
request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')
次に、csrf
トークンがrequest.METAから正しく取得されていることを確認します
4)ヘッダーなどを変更する必要がある場合-設定ファイルでその変数を変更します
1つのCSRFトークンがすべてのセッションに割り当てられます(つまり、ログインするたびに)。したがって、ユーザーが入力したデータを取得し、csrf_protectデコレーターで保護されている関数へのajax呼び出しとして送信する前に、ユーザーからこのデータを取得する前に呼び出されている関数を見つけてください。例えば。ユーザーがデータを入力するテンプレートをレンダリングする必要があります。そのテンプレートは、何らかの機能によってレンダリングされています。この関数では、次のようにcsrfトークンを取得できます。csrf = request.COOKIES ['csrftoken']ここで、問題のテンプレートがレンダリングされているコンテキスト辞書でこのcsrf値を渡します。このテンプレートに次の行を記述します。javascript関数で、ajaxリクエストを行う前に、次のように記述します。 csrf。これで、ajax呼び出しを行いながら、投稿データでこの値も渡します: "csrfmiddlewaretoken":csrf
これは、Djangoフォームを実装していない場合でも機能します。
実際、ここのロジックは次のとおりです。リクエストから取得できるトークンが必要です。したがって、ログイン直後に呼び出される関数を把握する必要があります。このトークンを取得したら、別のajax呼び出しを行って取得するか、ajaxからアクセス可能なテンプレートに渡します。
現在の回答のどこにも記載されていないため、テンプレートに埋め込みではない jsの場合の最速の解決策は次のとおりです。
テンプレートのscript.jsファイルへの参照の前に<script type="text/javascript"> window.CSRF_TOKEN = "{{ csrf_token }}"; </script>
を置き、jsファイルのcsrfmiddlewaretoken
辞書にdata
を追加します。
$.ajax({
type: 'POST',
url: somepathname + "do_it/",
data: {csrfmiddlewaretoken: window.CSRF_TOKEN},
success: function() {
console.log("Success!");
}
})
Djangoが提供する冗長性の低いソリューションを次に示します。
<script type="text/javascript">
// using jQuery
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
// set csrf header
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
// Ajax call here
$.ajax({
url:"{% url 'members:saveAccount' %}",
data: fd,
processData: false,
contentType: false,
type: 'POST',
success: function(data) {
alert(data);
}
});
</script>
私の場合、問題はメインサーバーから一時的なサーバーにコピーしたnginxの設定にあり、プロセスの2番目のサーバーではhttpsが無効になっています。
私はそれを再び機能させるために設定のこれらの2行をコメントアウトする必要がありました:
# uwsgi_param UWSGI_SCHEME https;
# uwsgi_pass_header X_FORWARDED_PROTO;