web-dev-qa-db-ja.com

Djangoを使用したCSRF、Axiosを使用したReact + Redux

これは教育プロジェクトであり、生産用ではありません。これの一部としてユーザーログインをするつもりはありませんでした。

POST=への呼び出しをDjangoにユーザーログインせずにCSRFトークンで実行できますか?jQueryを使用せずにこれを実行できますか? 、そして確かにいくつかの概念を融合しています。

JavaScript側については、この redux-csrf パッケージが見つかりました。 Axiosを使用してPOSTアクションと組み合わせる方法がわかりません:

_export const addJob = (title, hourly, tax) => {
  console.log("Trying to addJob: ", title, hourly, tax)
  return (dispatch) => {
    dispatch(requestData("addJob"));
    return axios({
      method: 'post',
      url: "/api/jobs",
      data: {
        "title": title,
        "hourly_rate": hourly,
        "tax_rate": tax
      },
      responseType: 'json'
    })
      .then((response) => {
        dispatch(receiveData(response.data, "addJob"));
      })
      .catch((response) => {
        dispatch(receiveError(response.data, "addJob"));
      })
  }
};
_

Django側で、私は このドキュメント CSRFについて、そして this をクラスベースのビューでの一般的な作業について読みました。

これまでの私の見解は次のとおりです。

_class JobsHandler(View):

    def get(self, request):
        with open('./data/jobs.json', 'r') as f:
            jobs = json.loads(f.read())

        return HttpResponse(json.dumps(jobs))

    def post(self, request):
        with open('./data/jobs.json', 'r') as f:
            jobs = json.loads(f.read())

        new_job = request.to_dict()
        id = new_job['title']
        jobs[id] = new_job

        with open('./data/jobs.json', 'w') as f:
            f.write(json.dumps(jobs, indent=4, separators=(',', ': ')))

        return HttpResponse(json.dumps(jobs[id]))
_

_csrf_exempt_ デコレーターを使用してみましたが、今のところこれについて心配する必要はありませんが、それがどのように機能するかはわかりません。

テンプレートに_{% csrf_token %}_を追加しました。

これは私のgetCookieメソッドです(Django= docs)から盗まれました):

_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 = cookies[i].trim();
            // 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;
}
_

読みました Axios CSRF情報を変更する必要があること:

_var axios = require("axios");
var axiosDefaults = require("axios/lib/defaults");

axiosDefaults.xsrfCookieName = "csrftoken"
axiosDefaults.xsrfHeaderName = "X-CSRFToken"
_

getCookie('csrftoken')の呼び出しから取得した値である実際のトークンをどこに貼り付けますか?

39
Reed Dunkle

3つの方法があります。各axios呼び出しのヘッダーにトークンを手動で含めるか、各呼び出しでaxiosのxsrfHeaderNameを設定するか、デフォルトのxsrfHeaderNameを設定できます。

1.手動で追加する

csrfTokenという変数にトークンの値が格納されているとしましょう。 axios呼び出しでヘッダーを設定します。

// ...
method: 'post',
url: '/api/data',
data: {...},
headers: {"X-CSRFToken": csrfToken},
// ...

2.呼び出しでxsrfHeaderNameを設定します。

これを追加:

// ...
method: 'post',
url: '/api/data',
data: {...},
xsrfHeaderName: "X-CSRFToken",
// ...

次に、settings.pyファイル、次の行を追加します。

CSRF_COOKIE_NAME = "XSRF-TOKEN"

3.デフォルトヘッダーの設定[1]

各呼び出しでヘッダーを定義する代わりに、axiosのデフォルトヘッダーを設定できます。

Axiosをインポートして呼び出しを行うファイルで、インポートの下にこれを追加します。

axios.defaults.xsrfHeaderName = "X-CSRFToken";

次に、settings.pyファイル、次の行を追加します。

CSRF_COOKIE_NAME = "XSRF-TOKEN"

Edit2017年6月10日):ユーザー@yestemaは、Safariではわずかに異なる動作をすると言います[2]

編集2019年4月17日):ユーザー@GregHolstによると、上記のSafariソリューションは機能しません彼のために。代わりに、MacOS Mojave上のSafari 12.1に対して上記のソリューション#3を使用しました。 (コメントから

編集2019年2月17日):設定が必要な場合もあります[3]

axios.defaults.withCredentials = true

質問:この次のセクションは誰にとっても有用ですか?ソリューションを含めるだけでこの答えが改善されるのではないかと思っています。意見があれば教えてください。

混乱:

Django Docs

まず、 Django docs James Evans 参照 からのパッセージ全体:

...各XMLHttpRequestで、カスタムX-CSRFTokenヘッダーをCSRFトークンの値に設定します。多くのJavaScriptフレームワークには、リクエストごとにヘッダーを設定できるフックが用意されているため、これは簡単です。

最初のステップとして、CSRFトークン自体を取得する必要があります。トークンの推奨ソースはcsrftoken Cookieです。これは、上記で概説したようにビューのCSRF保護を有効にした場合に設定されます。

注意

CSRFトークンCookieはデフォルトでcsrftokenという名前になっていますが、CSRF_COOKIE_NAME設定を介してCookie名を制御できます。

CSRFヘッダー名はデフォルトでHTTP_X_CSRFTOKENですが、CSRF_HEADER_NAME設定を使用してカスタマイズできます。


Axios Docs

これは Axios docs からのものです。 csrftokenを含むCookieの名前とヘッダーの名前をここで設定したことを示しています。

  // `xsrfCookieName` is the name of the cookie to use as a value for xsrf token
  xsrfCookieName: 'XSRF-TOKEN', // default

  // `xsrfHeaderName` is the name of the http header that carries the xsrf token value
  xsrfHeaderName: 'X-XSRF-TOKEN', // default

条項

私の質問に示されているように、Cookieにはdocument.cookie。私が持っている唯一のCookieは、Django=テンプレートに入れたCSRFトークンです。以下に例を示します。

csrftoken=5knNceCUi9nL669hGGsvCi93XfqNhwTwM9Pev7bLYBOMXGbHVrjitlkKi44CtpFU

これらのドキュメントには、混乱を招くような概念がいくつかあります。

  • CSRFトークンを含むCookieの名前。 In Djangoこれはデフォルトでcsrftokenであり、Cookieの等号の左側にあります。
  • 実際のトークン。これは、Cookieの等号の右側にあるすべてです。
  • トークン値を運ぶhttpヘッダー。

私が試したものは動作しませんでした: 12

34
Reed Dunkle

axios.defaults.xsrfCookieName = "XCSRF-TOKEN";およびCSRF_COOKIE_NAME = "XCSRF-TOKEN"

動作しないApple Mac OS上のSafari

MAC Safariのソリューションは簡単です変更XCSRF-TOKENからcsrftoken

そのため、js-codeでは次のようになります。

    import axios from 'axios';
    axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
    axios.defaults.xsrfCookieName = "csrftoken";

Settings.pyで:

    CSRF_COOKIE_NAME = "csrftoken"
14
yestema

この設定は問題なく機能します Config axios CSRF Django

import axios from 'axios'

/**
 * Config global for axios/Django
 */
axios.defaults.xsrfHeaderName = "X-CSRFToken"
axios.defaults.xsrfCookieName = 'csrftoken'

export default axios
9
krescruz

「簡単な方法」はほとんど私のために働いた。これはうまくいくようです:

import axios from 'axios';
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
axios.defaults.xsrfCookieName = "XCSRF-TOKEN";

そして、settings.pyファイルで:

CSRF_COOKIE_NAME = "XCSRF-TOKEN"
4
cran_man

Djangoが提供するCSRFトークンをすべての投稿リクエストに手動で追加できますが、それは面倒です。

Django docs から:

上記のメソッド(手動でCSRFトークンを設定する)はAJAX POSTリクエストに使用できますが、いくつかの不便:POSTリクエストごとにPOSTデータとしてCSRFトークンを渡すことを忘れないでください。このため、別の方法があります。各XMLHttpRequestで、カスタムX-CSRFTokenヘッダーをCSRFトークンの値に設定します。多くのJavaScriptフレームワークには、リクエストごとにヘッダーを設定できるフックが用意されているため、これは簡単です。

ドキュメントには、CSRFトークンCookieからCSRFトークンを取得し、AJAXリクエストのヘッダーに追加するために使用できるコードがあります。

1
James Evans

実際にこれを行うには本当に簡単な方法があります。

追加 axios.defaults.xsrfHeaderName = "X-CSRFToken";をアプリの構成に設定してからCSRF_COOKIE_NAME = "XSRF-TOKEN"はsettings.pyファイルにあります。魅力のように機能します。

1
Dave Merwin

私にとっては、Djangoは送信したヘッダーをリッスンしていませんでした。APIにカールできましたが、axiosでアクセスできませんでした。 cors-headers package ...それはあなたの新しい親友かもしれません。

Django-cors-headersをインストールして修正しました

pip install Django-cors-headers

そして追加

INSTALLED_APPS = (
    ...
    'corsheaders',
    ...
)

そして

MIDDLEWARE = [  # Or MIDDLEWARE_CLASSES on Django < 1.10
    ...
    'corsheaders.middleware.CorsMiddleware',
    'Django.middleware.common.CommonMiddleware',
    ...
]

私のsettings.pyに

私も持っていました

ALLOWED_HOSTS = ['*']
CORS_Origin_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
CORS_EXPOSE_HEADERS = (
    'Access-Control-Allow-Origin: *',
)

私のsettings.pyでそれはおそらくやり過ぎです

1
spinach

Yestemaが言ったこと(およびkrescruz、cran_man、Dave Merwin et。alによってエコーされたもの)に加えて、以下も必要です。

axios.defaults.withCredentials = true
0
sureshvv