目的:Djangoでajaxを利用したい時にすぐ参照できるように、必要な情報をコンパクトにまとめておく。
対象読者:Djangoユーザー
概要:DjangoにはCSRF対策が入っている関係上、ajaxを利用するためには以下のような作業が必要です。
動作サンプル:https://whiteblack-cat.info/ja-jp/ajax_sample/
ソースコード:https://github.com/ccat/django_ajax_sample
1. 背景(またはどうしてajaxを利用したいのにできないのか)
Djangoには入力フォームの生成と入力データの取得を補助する強力な仕組みが存在するため、 ちょっとしたアプリを作成する分には何の苦労もなくPOSTでデータを送信することができます。 しかし、JavascriptでPOST送信を行おうとすると、途端に403 Forbiddenで悩まされることになります。
これは、DjangoがCSRF対策が
デフォルトで有効になっているためです。
CSRF対策をOFFにすることも可能ですが、セキュリティ上の脆弱性が出来てしまうため、リスクを十分に把握した上でなければお勧めできません。
そこで、CSRF対策をONにしたままajaxを利用する方法を記載します。
なお、本内容はhttps://docs.djangoproject.com/en/1.7/ref/contrib/csrf/#ajax
の内容を、より具体的に整理したものです。
Django Webアプリケーション一式のサンプルコードは以下からダウンロードできます。
https://github.com/ccat/django_ajax_sample
テンプレートとurl、viewがセットになっており、そのままDjangoプロジェクトに組み込めば動作をテストできます。
また、本サンプルコードは下記で動作しています。
https://whiteblack-cat.info/ja-jp/ajax_sample/
2. 事前作業(ajaxを利用するために1度行えばよい作業)
まず、以下のコードをstaticかどこかに保存してください。
こちらからダウンロードするのが簡単です。
//Cite : https://docs.djangoproject.com/en/1.5/ref/contrib/csrf/#ajax
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');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function sameOrigin(url) {
// test that a given url is a same-origin URL
// url could be relative or scheme relative or absolute
var host = document.location.host; // host + port
var protocol = document.location.protocol;
var sr_origin = '//' + host;
var origin = protocol + sr_origin;
// Allow absolute or scheme relative URLs to same origin
return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
(url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
// or any other URL that isn't scheme relative or absolute i.e relative.
!(/^(\/\/|http:|https:).*/.test(url));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
// Send the token to same-origin, relative URLs only.
// Send the token only if the method warrants CSRF protection
// Using the CSRFToken value acquired earlier
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
次に、ajaxを利用するページのテンプレートに、下記コードを埋め込んでください。 なお、1行目で分かる通り、本内容はjqueryを利用することを前提としています。 また、2行目は上記のスクリプトを/static/js/配下のdjangoajax.jsと言う名称で保存したと仮定しています。別の場所、名称で保存した場合は変更してください。
<script type="text/javascript" charset="UTF-8" src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <script type="text/javascript" charset="UTF-8" src="/static/js/djangoajax.js"></script>
この2つを行えば事前作業は終了です。
3. ajaxの使い方(ajaxを利用するために毎回必要な作業)
以下のサンプルコードのように、jqueryのpostとコールバックを利用して、普段通りajaxのコードを作成してください。
<script type="text/javascript">
function callback(data, status) {
$("#echoResult").text("status:"+status+" data:"+data);
}
function sends() {
$.post('/ajax_sample/input/',{"echo": $("#echo").val()},callback,"html");
}
</script>
<form action="#" method="post">
{% csrf_token %}
<input type="text" name="echo" id="echo" />
<input type="button" value="submit" onclick="sends()" />
</form>
4. 仕組み(または如何にしてajaxを利用できるようにしているのか)
CSRF対策では、ページが表示されるたびにランダムな文字列(CSRF Token)を生成し、それをPOSTに含めることで 「ページを表示した人」と「POSTを送信してきた人」を識別しています。 jqueryデフォルトのpost関数ではCSRF Tokenを送信しないため、そこでDjangoがエラーを出力します。
そこで、djanoajax.jsではCSRF TokenをCookieから読み込み、jqueryのpost関数が呼び出された時に、 CSRF TokenをPOSTのデータに含めるように変更を行っています。
0 件のコメント:
コメントを投稿