質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Vue CLI

Vue CLIは、Vue.jsでアプリケーション開発を行うためのコマンドラインインタフェース(CLI)に基づいた開発ツールです。インタラクティブなプロジェクトの雛形や設定なしで使用できるプロトタイプの作成など、さまざまな機能が用意されています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

3542閲覧

Vue.jsとDjangoを用いて非同期処理を行う方法

study_111

総合スコア82

Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Vue CLI

Vue CLIは、Vue.jsでアプリケーション開発を行うためのコマンドラインインタフェース(CLI)に基づいた開発ツールです。インタラクティブなプロジェクトの雛形や設定なしで使用できるプロトタイプの作成など、さまざまな機能が用意されています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

1グッド

0クリップ

投稿2020/08/04 15:56

編集2020/08/04 16:02

DjangoとVue.jsにおいて、アプリを開発する際に、フロント側をVue.js、APIサーバーとしてDjangoを使用していた場合にどのようにして、CSRF対策を行うかといった部分でつまずいてしまっています。
ユーザーがURLからトップページなどにアクセスした場合に、表示されるファイルは、「Vueファイル」であるかと思います。
実際に表示されたファイルがForm画面であり、ユーザーが値を入力後、axiosによってDjango側にPOSTリクエストを行なった場合、CSRFトークンを投げなかった場合に、認証エラーとなってしまいます。
ここで疑問なのですが、Djangoのテンプレートを使用していた場合は、{ % csrf_token %}とすることで、トークンが自動で付与されましたが、Vueファイルの場合はそのようなことが出来ません。
その為、どこかでDjangoからCSRFトークンをブラウザ側へ投げる、もしくはCSRFを突破する別の方法が必要であるかと思いますが、その方法が現状見つからない状況です。

Vue側はVueCliでプロジェクトを作成し、開発を進めている段階です。
以下は、axiosを用いてDjango側へリクエストを投げるVueファイルになります。

<template> <div> <h1>test-site</h1> <h5>test</h5> <p v-if="errors.length"> <b>Please correct the following error(s):</b> <ul> <li v-for="(error,index) in errors" :key="index">{{ error }}</li> </ul> </p> <form action="" method="get" v-on:submit.prevent="submit"> <input type="text" v-model="inputUrl" name="url" placeholder="http://example.com"> <button type="submit">送信</button> </form> </div> </template> <script> import axios from 'axios' import Cookies from 'js-cookie' export default { data() { return { errors:[], inputUrl:'', csrftoken:'', } }, methods: { submit(){ this.errors = []; this.csrftoken = Cookies.get('csrftoken'); console.log('csrftoken: ' , this.csrftoken); if(!this.inputUrl){ this.errors.push('URLを入力して下さい') }else if(!this.checkFormat(this.inputUrl)){ this.errors.push('URLが正しくありません') } if (!this.errors.length){ axios.post( '/polls/check/', this.inputUrl, { headers:{ 'X-CSRFToken':this.csrftoken } } ) .then(response => { console.log(response) }) .catch(error => { console.log(error) }) } }, checkFormat(url){ var re = /^http(|s)://.+/ return re.test(url); } }, } </script>

現状、Vue側では、this.csrftoken = Cookies.get('csrftoken');にてクッキーの取得を行っていますが、当然Django側へアクセスをしていない為、CSRFトークンは存在せずundefinedとなってしまっています。
CSRFトークンに関してはDjangoのドキュメントを読み、CSRFトークンを取得する方法は分かったのですが、送信する方法は分かりませんでした。
こちらの問題につきまして、解決策が見当たらない状況な為、ご助言頂けましたら幸いです。

clearcat👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/08/04 17:38

djangoはよく分かりませんが、リンク先のドキュメントに書かれているとおり、CSRFトークンはdjangoのミドルウェアによってクッキー(HTTPレスポンスヘッダー)に設定されているので、{ % csrf_token %}でフォームにhiddenなinputが出力されなくてもクッキーに設定はされているのではないかと思います。クッキー取得時にundefinedになっているなら、HTTPレスポンスヘッダを確認してください。なければ設定の問題だと思います。 axiosを使ったajaxによる非同期処理ではX-CSRFTokenにクッキーに書かれた内容と同じものを設定することでサイトが用意したページからリクエストしてるという判定になるのではないかと思います。axiosの使い方自体は調べてないので分かりませんが、なんとなく合ってる風に見えます。動かなければ別途確認してください。 全体的にコードも環境説明も中途半端でよく分からないので、原因も不明→回答は私には不可能です。 なお、vueは無関係だと思います…ただのUI(部品)なので…
study_111

2020/08/04 23:44 編集

>CSRFトークンはdjangoのミドルウェアによってクッキー(HTTPレスポンスヘッダー)に設定されているので こちらですが、Django側にアクセスした場合はトークンは設定されるかと思うのですが、Vueファイルによる表示を行っていた場合は、アクセスはVue側へ行う為、トークンが生成出来ないといった状況です...
退会済みユーザー

退会済みユーザー

2020/08/04 23:49 編集

vue.js自身はクライアント側で動くjavascriptなのでサーバーとしての機能はありません。 クッキーを返すのはサーバーの仕事です。 djangoにアクセスしていないとしたら、一体どこから取ってきた何を表示したと言っているのかサッパリ分かりませんよ。 環境の説明をきちんとしてください。
study_111

2020/08/04 23:53

>vue.js自身はクライアント側で動くjavascriptなのでサーバーとしての機能はありません。 こちら勿論そうなのですが、今回はVueCliによるプロジェクトを作成しており、「index.html」などを返すのではなく、Vueファイルを返す形でページの表示を行っているといった状況です。
退会済みユーザー

退会済みユーザー

2020/08/04 23:57

webpackの開発サーバーをそのまま使用してるということですか?最終的にもそういう運用なのですか?
study_111

2020/08/05 00:05 編集

自分はVueの経験があまりなく、良く分かっていない場合は多いのですが、最終的には開発サーバーではなくAWSでサーバーを構築し運用していこうと考えています。 しかしながら、Vue側でVueファイルを返す形とした場合は、Django側のプログラム処理を行わない為、CSRFトークンがクッキーに付与され、返されるといったことは起こり得ないのではないかと思っているのですが、そういった訳ではないのでしょうか?
退会済みユーザー

退会済みユーザー

2020/08/05 00:26

最終的にサーバーや構成すら決まってない段階で、CSRFとかどうしたいのでしょうか?何をしたいのでしょう?今やっているのは仕事ですか?趣味ですか?仕事であれば、ちゃんと設計してください。できなければできる人にお金を払って頼んでください。
guest

回答2

0

ベストアンサー

やはりCSRFの制限がある限り、DjangoからVueアプリをサーブしなきゃいけなさそうです。

肝心なのは、Django 側に django-webpack-loader と、Vue 側に webpack-bundle-tracker です。

Vue 側に webpack-bundle-tracker をインストール:

npm install --save-dev webpack-bundle-tracker

Vue 側に、 vue.config.js で下記のように設定してください:

javascript

1// vue.config.js 2const BundleTracker = require("webpack-bundle-tracker"); 3 4module.exports = { 5 publicPath: "http://0.0.0.0:8080/", 6 outputDir: "dist", 7 8 configureWebpack: { 9 plugins: [ 10 new BundleTracker({ filename: './webpack-stats.json' }), 11 ], 12 }, 13};

設定値を説明します:

publicPath は相対リンクの root です。django-webpack-loader によって、ポートが8080です。
outputDir はトランスパイルの結果ファイルの置き場です。後でDjangoに知らせます。
configureWebpack に BundleTracker のプラグインを設定します。その追跡ファイルも後でDjangoに知らせます。

Django 側に、django-webpack-loader をインストール:

pip install django-webpack-loader

Django 側に、settings.py で下記のように設定してください:

python

1// settings.py 2... 3 4STATICFILES_DIRS = [ 5 os.path.join(BASE_DIR, 'dist'), 6] 7 8... 9 10WEBPACK_LOADER = { 11 'DEFAULT': { 12 'BUNDLE_DIR_NAME': '', 13 'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'), 14 } 15} 16 17... 18 19INSTALLED_APPS = ( 20 ... 21 'webpack_loader', 22) 23 24... 25 26TEMPLATES = [ 27 { 28 'BACKEND': 'django.template.backends.django.DjangoTemplates', 29 'DIRS': [ 30 os.path.join(BASE_DIR, 'templates'), 31 ], 32 'OPTIONS': { 33 'context_processors': [ 34 'django.template.context_processors.debug', 35 'django.template.context_processors.request', 36 'django.contrib.auth.context_processors.auth', 37 'django.contrib.messages.context_processors.messages', 38 ], 39 }, 40 } 41] 42

設定値を説明します:

STATICFILES_DIRS は静的なファイルの置き場です。先の outputDir をここに入れます。
BUNDLE_DIR_NAME は Vue の出力場所です。dist に直接出力なので、空にします。
STATS_FILE は BundleTracker の追跡ファイルです。先の追跡ファイルをここに入れます。
INSTALLED_APPS で webpack_loader を最後に入れます。
TEMPLATES で設定するフォルダに下記のテンプレートを入れます。

html

1// templates/application.html 2{% load render_bundle from webpack_loader %} 3{% render_bundle 'app' %}

そして、urls.py で下記のように設定してください:

python

1// urls.py 2from django.views.generic import TemplateView 3 4urlpatterns = [ 5 path('admin/', admin.site.urls), 6 path("", 7 TemplateView.as_view(template_name="application.html"), 8 name="app", 9 ), 10]

上記のように設定したら、二つのターミナルを用意して、下記二つの命令をそれぞれに実行してください:

npm run serve python manage.py runserver

そうしたら、ブラウザーで http://127.0.0.1:8000 に訪問すれば、アプリが作動しているはずです。


参照

投稿2020/08/06 03:00

編集2020/08/09 00:21
YufanLou

総合スコア464

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

study_111

2020/08/06 04:23 編集

ご親切、及びご丁寧にご回答頂きましてありがとうございます。 ご提示頂きました手順通り試してみたのですが、2点程エラーが発生してしまいました。 恐らく、こちら自分が元々作成していたファイルなどが原因の可能性もあります為、一度プロジェクトフォルダごとGitHubにアップロード致します為、そちらをご確認頂くこと出来ませんでしょうか。 こちらの質問に全てのファイルを掲載しますと文字数制限に引っかかってしまうことや、仕事の都合上載せられない部分も出てきてしまいます為、GitHubのプライベートリポジトリの方で、ご確認頂きたく存じております。 お手数をおかけし申し訳ないのですが、何卒ご検討頂けましたら幸いです。
study_111

2020/08/09 00:15 編集

↑こちらの件ですが、実際に起きてしまったエラーは、以下となります。 > ?: (admin.E402) 'django.contrib.auth.context_processors.auth' must be enabled in DjangoTemplates (TEMPLATES) if using the default auth backend in order to use the admin application. ?: (admin.E404) 'django.contrib.messages.context_processors.messages' must be enabled in DjangoTemplates (TEMPLATES) in order to use the admin application.
YufanLou

2020/08/09 00:30

TEMPLATES の中に OPTIONS.context_processors を設定する必要がありそうです。回答に修正しました。 他のブログを読んでみたら、SPA向けに決まったら、APIサーバーがCSRF保護を除いて、API TokenとかAPIサーバー用の認証策を使えばいかがかと思っています。https://www.django-rest-framework.org/ とか。
study_111

2020/08/09 02:26 編集

ありがとうございます。 ご追記頂きました、「OPTIONS.context_processors 」を加えましたら、エラーが解消出来、正常に開発サーバーを起動出来ました。 しかし、度々申し訳ないのですが、Django側へリクエストを送った際に、「Forbidden (CSRF cookie not set.): /polls/check/」となってしまい、レスポンスが拒否されてしまっている状況です。 また、少々疑問があるのですが、リクエストを送った後、NetworkタブのHeadersを確認してみますと、「Request URL: http://localhost:8080/polls/check/ 」とポートが「8000」ではなく「8080」となっているのですが、Django側へはリクエストが送れている状態です。 こちらは何故このようなことが可能なのでしょうか...?
YufanLou

2020/08/09 11:48

そうですか。やはりSPAはCSRF保護と相性が悪いですね。下記のブログシリーズを参照すればいかがでしょうか? Django REST Framework なら、APIサーバーとして特化しCSRF Tokenの代わりにAPI Token使うことになります。 https://qiita.com/Butterthon/items/95b05c15bce419846f27
study_111

2020/08/10 01:01

ご丁寧にありがとうございます。 一度、CSRF保護の対策について、教えて頂きました「API Token」などで考えてみたいと思います。 今回は、長々とご協力頂きまして、誠にありがとうございました。
guest

0

Postする際に、設定する

Axiosを投げる際に、下記のように設定しておけばCSRFは通るかと思います。

axios.defaults.xsrfCookieName = 'csrftoken' axios.defaults.xsrfHeaderName = "X-CSRFTOKEN" axios.post('url') .then() .catch()

自作プラグインを作成してデフォルトで設定する

また、puluginsディレクトリ等に、http.jsなどの名前で自作プラグインを作成することでデフォルトでこの設定することも可能です。

javascript

1// plugins/http.js 2import Vue from 'vue' 3import axios from 'axios' 4 5export default { 6 install: (Vue, options) => { 7 const http = axios.create({ 8 xsrfCookieName:'csrftoken', 9 xsrfHeaderName:"X-CSRFTOKEN", 10 }) 11 Vue.prototype.$axios = http 12 } 13} 14

javascript

1// main.js 2import http from '@/plugins/http' 3Vue.use(http)

Vue

1methods: { 2 post () { 3 this.$axios('url') 4 .then() 5 .catch() 6 } 7}

ところどころ省略はしていますが、だいたいこんな感じでいけると思います。
お役に立てれば幸いです。

投稿2020/08/05 13:24

stakizawa

総合スコア117

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

study_111

2020/08/05 14:47

ご回答ありがとうございます。 以下の部分を追記しDjangoへリクエストを送ってみたのですが、「 403 forbidden 」となってしまいました。 「 axios.defaults.xsrfCookie = 'csrftoken' 」 「 axios.defaults.xsrfHeaderName = "X-CSRFTOKEN" 」
stakizawa

2020/08/06 02:03

一応確認なのですが、cookieにcsrftokenはありますでしょうか? 確認方法としては、chromeの場合、デベロッパーツールから「Application」タブを選択して、Storageの欄にCookieがあるかと思います。 そこに以下のような情報があるか確認していただけますでしょうか。 Name:csrftoken Value: <生成されたtoken>
study_111

2020/08/06 02:35 編集

ブラウザはfirefoxを使用しているのですが、デベロッパーツールから確認したのですが、「csrftoken」は見当たりませんでした。
stakizawa

2020/08/06 02:43 編集

となるとおそらく、DjangoとVueが別オリジンとして動いているためVue側にてDjangoが生成したcsrftokenを取得できないのが原因なのかなと思います。 djangoのsettings.pyに下記のコードを追加して再度、試してみてください。 ``` if DEBUG: INSTALLED_APPS += ['corsheaders'] MIDDLEWARE = ['corsheaders.middleware.CorsMiddleware'] + MIDDLEWARE CORS_ORIGIN_WHITELIST = ( 'http://localhost:8080', ) ```
study_111

2020/08/06 02:56

ご返信ありがとうございます。 まさしく、ご指摘の通りでして、現在はVueCliで「npm runserve」として開発サーバーを立ち上げ、Django側では「python manage.py runserver」としてこちらでも開発サーバーを立ち上げている状態です。 少々、Vueを用いた開発において、疑問だったのですが、仮に本番サーバーでの運用になった場合、Django側をAPIサーバーとしてしか使用しておらず、ユーザーがアクセスした際はDjangoテンプレートではなく、Vueファイルを返すことになった場合、Django側ではCSRFトークンは発行されないものと思ったのですが、CSRFトークンというものはDjangoなどのプログラムにより発行されるものなのでしょうか? または、サーバー側で自動で作成し、レスポンスとして返ってくるものなのでしょうか? 勉強不足で申し訳ないのですが、ご助言頂けましたら幸いです。
study_111

2020/08/06 03:13 編集

「if DEBUG: INSTALLED_APPS += ['corsheaders'] MIDDLEWARE = ['corsheaders.middleware.CorsMiddleware'] + MIDDLEWARE CORS_ORIGIN_WHITELIST = ( 'http://localhost:8080&#039;, )」 こちら試してみましたら、ブラウザ側で「CSRFトークン」は設定されていなかったのですが、リクエストをDjango側へ送信することが出来ました。 ありがとうございます。
stakizawa

2020/08/06 04:19

>>> Django側ではCSRFトークンは発行されないものと思ったのですが、CSRFトークンというものはDjangoなどのプログラムにより発行されるものなのでしょうか? その通りだと思います。 djangoのcsrfのミドルウェアを通ってくる際に、tokenが存在しない場合は、tokenを設定する処理が存在します。
study_111

2020/08/06 04:25 編集

ご返信ありがとうございます。 そうなりますと、やはり現状の方法ですと、一度はDjango側へアクセスをし、ブラウザへレスポンスを返さなければならないといった訳だったのですね。
stakizawa

2020/08/06 04:38

私も最近VueとDjangoの勉強を始めたばかりなので、何とも言えませんがそういうことなのかと思います。 ちなみに私の後学のために教えていただきたいのですが、一度リクエストを送った後はVue側のCookieにはtokenが入っているのでしょうか??
study_111

2020/08/08 04:55 編集

>一度リクエストを送った後はVue側のCookieにはtokenが入っているのでしょうか?? こちらですが、自分も良く分からないのですが、何故かChromeの方ではcsrftokenが入っているのですが、firefoxの方では、レスポンスのstatus_codeが200となっているのですが、何故かクッキーにセットされないままなのですよね...
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問