- 投稿日:2020-09-08T23:44:38+09:00
axiosをグローバルに呼び出す
設定する
src/main.jsimport Vue from 'vue'; import axios from 'axios'; . . . Vue.prototype.$http = axios.create( { baseURL: process.env.VUE_APP_API_URI, withCredentials: true }, );呼び出す
. . . methods: { fetchItemList() { return new Promise((resolve) => { this.$http.get('/api/v1/items').then((response) => { this.itemList = response.data.index; resolve(); }).catch(省略); }); }, }, . . .みたいな感じで
this.$http
で呼び出せますおしまい
- 投稿日:2020-09-08T21:59:15+09:00
rails + vue.js でテンプレートインジェクション対策をする
テンプレートインジェクションって?
テンプレートエンジンやjsのフレームワークを使用しているアプリケーションに対して、文字列展開される記法を利用して、santizeの漏れをつき任意のプログラムを実行させる攻撃方法の一つです。
広義のxssに近いような攻撃ですね。
例えばサーバーサイドをrails、フロントエンドをvue.jsという構成でアプリケーションが作成され、
一般ユーザーから入力を受け付けて表示する機能があるとします。ここで悪意のあるユーザーが、攻撃対象のwebサイトが使用しているフロントエンドフレームワークをvue.jsだと仮定して攻撃します。
文字列の展開に使われる{{を使用して以下の文字列を入力してきました。{{constructor.constructor('alert(1111111111)')()}}現状のrailsの仕様だと、
部分的に文字列表示をrailsで行っている箇所で {{ マスタッシュがエスケープの対象になっていません。
なので、vue.jsのテンプレートと解釈されて中の文字列がjsとして実行されてしまいます。なぜ、これが怖いのか?
という説明を今さらしてもあれなのですが、この中で任意のjsを実行できると訪問したユーザーの情報を他サーバーに送信するなどなんでもできちゃいますよね。
対応
でどうやって対応したの?
まあセキュリティ対策の基本で入力で弾く&出力で置き換えるをやっていきます。入力部分での対応
入力時にマスタッシュ文字がある場合弾いてあげます。
controllerがパラメーターを受け取る前後で対応するか、modelの保存直前で対応するか迷ったのですが、
railsのstrong parameterをいじるのが難しかったので、modelで対応しています。class BaseModel < ApplicationRecord self.abstract_class = true def delete_vue_template string_value_keys = self.attributes.map do |key, value| key if value.class == String end string_value_keys.compact!.each do key self[key].replace('{{', '{ {').replace('}}', '} }') end end end該当のmodelに
before_validation :delete_vue_templateを記載してあげています。
出力部分での対応
大体のrailsアプリケーションでsanitizeが使われていたり、simple_formatで内部的に呼ばれているかなと思いますので、そこに手を入れて行こうとと思います。
ApplicationHelperにsanitizeメソッドを作成して、オーバーライドしてあげます。
simple_formatを使っている方も多いと思いますのでそちらでも自動で適用されるよう工夫していますdef simple_format(string, options = {}) super(sanitize(string, tags: %w[p br strong]), options) end def sanitize(html, options = {}) html.replace('{{', '{ {') if html.class == String super(html, options) end感想&追記
セキュリティ検査を会社で行い、対応しようと思った際にあまり資料がなかったのでrails&vue.jsのアプリケーション向けに資料に致しました。
もっとこうやった方いいとか、記載に誤りや視点に抜け漏れがあった際にはコメント等頂けると嬉しいです。
編集リクエストでも助かります。他の対応方法
angular.jsのドキュメントには一部記載があります。
https://angular.jp/guide/security#offline-template-compilerオフライン・テンプレート・コンパイラはテンプレートインジェクションと呼ばれる脆弱性を確実に防止し アプリケーションのパフォーマンスを大幅に向上させます。プロダクション環境ではオフラインテンプレートコンパイラを使い、 動的にテンプレートを生成しないようにしましょう。Angularはテンプレートコードを信頼するので、 テンプレート、特にユーザーデータを含むテンプレートを生成すると、Angularの組み込みの保護が回避されます。 Angularはテンプレート文字列を全面的に信頼するため、動的なテンプレート生成は常にXSSの危険性を有します。フォームを安全に動的に構築する方法については Dynamic Forms のガイドを参照してください。
既にリリースしていてこの機能を使っているなら変更する手間がかなり大きいですが、動的テンプレートを生成しないようにしておくのもいいかなと思います。
- 投稿日:2020-09-08T19:06:08+09:00
AppServiceで.NetCore Identity認証をするとnoscriptのHttpが返ってくる
現象
AppServiceに公開しているVue.jsで作成したWebアプリで.NetCoreIdentityによる認証を行っているが、
認証に失敗した場合に、responseとしてnoscriptタグが記載してあるHttpが返ってくる。
(ローカルでは正しく判定される)作りとしては単純で、vue-routerのbeforeEachでバックエンドへ認証の問い合わせを行い、失敗したらログイン画面に遷移させるというコード
index.jsrouter.beforeEach((to, from, next) => { authcontroller.auth() .then((x) => { next() }).catch(() => { next({ path: '/login', query: { redirect: from.fullPath } }) }) });Startup.cs<noscript> <strong>We're sorry but test doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> </noscript>原因
どうも.NetCoreIdentityの認証に失敗した場合、デフォルトではHttpStatusCode[302(Found)]が返却されるらしい。
これをAppServiceちゃんが良しなにリダイレクトしておかしくなってるっぽい。
(なぜローカルだと発生しないのかは不明)対策
認証失敗時のレスポンスコードを指定してやれば良い
Startup.cspublic void ConfigureServices(IServiceCollection services) { services .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options =>{ // 認証失敗時のステータスコードを変更 options.Events.OnRedirectToLogin = context => { context.Response.Headers["Location"] = context.RedirectUri; context.Response.StatusCode = 401; return Task.CompletedTask; }; }); }
- 投稿日:2020-09-08T18:11:04+09:00
Vueでコンポーネントの外側をクリックしたら閉じたい
dependencies
vue: 2.x目的
コンポーネントの外側、または他の部分をクリックしたら、そのコンポーネントを非表示にしたい。
ModalやDialogのようなコンポーネントはscrim(黒い背景のこと)を持つため、外側をクリックしたら閉じるという動きを作りやすい。実際scrimはコンポーネント内ですし。
そうではなく、Popupなどの軽率にフロートしてなおかつ外側をクリックしたら閉じてほしい、というコンポーネントはそれぞれが
document.onclick
に反応する必要がある。ググってみたらdirectiveで頑張っている例が多い。
- vue-click-outside
- Custom Directive
vue-click-outside
のコード
https://github.com/vue-bulma/click-outside/blob/master/index.jsハンドラを通したりSSRを想定する過程で少しhakkyになっているように見える。
ここではdirectiveの代わりにWrapper Componentでよりシンプルに解決したい。
Wrapper (Popup) Component
Popup.vue<template> <div @click.stop> <slot /> </div> </template> <script lang="ts"> import Vue from "vue"; export default Vue.extend({ methods: { onClickOutside(e: Event) { this.$emit("click-outside"); }, }, beforeMount() { document.addEventListener("click", this.onClickOutside); }, beforeDestroy() { document.removeEventListener("click", this.onClickOutside); }, }); </script>解説
beforeMount
とbeforeDestroy
はサーバーサイドレンダリングでは呼ばれない。
そのため、directiveで必要なサーバーか否かの判定は必要無くなる。ref: API — Vue.js
あと自身がクリックされた時にdocumentへ通知されないように、空の
@click.stop
を置いている。Usages
usage.vue<template> <PopOver v-if="popOver.isVisible" @click-outside="togglePopOver"> <div>{{ contents }}</div> </PopOver> </template> <script lang="ts"> import Vue from "vue"; export default Vue.extend({ data() { return { popOver: { isVisible: true } } }, methods: { togglePopOver() { this.$data.popOver.isVisible = !this.$data.popOver.isVisible; }, }, }); </script>解説
表示/非表示は
v-if
で判定してもいいし、PopOver
にpropsを渡して自身が判定する方法にしてもいい。
このサンプルではPopOver
は何のスタイルも持たず単なるdiv
としてDOM Treeには表示されるので、スタイルは好きに変更すれば良いのでは。
- 投稿日:2020-09-08T17:47:08+09:00
【Vue.js】ボタンの切り替えテクニック
モダンなサイトだと、ボタンをクリックしたらアイコンが切り替わって、内容が見れたりするようなUIも増えてきていますよね。
そんなボタンの切り替えの構造をVue.js(Nuxt.js)で表現していこうと思います!
ボタンを押すと、記事内容の表示・非常時を切り替えられる
ボタンをそして、あるデータの真偽値を変化させる
<v-btn @click="show = !show" icon> </v-btn><script> expprt default { data () { return { show: false } } } </script>ボタンを押すと、falseの真偽値が切り替わる
showの真偽値によって変化する者たち
<v-btn @click="show = !show" icon> <v-icon>{{ show ? 'mdi-chevron-up' : 'mdi-chevron-down' }}</v-icon> </v-btn>showの真偽値、そして三項演算子によって、アイコンの見た目が変わるようになっている。
<v-expand-transition> <div v-show="show"> <v-divider></v-divider> <v-card-text> <ul> <li v-for="item in items" :key="item.id"> <a href="item.url">{{ item.title }}</a> </li> </ul> </v-card-text> </div> </v-expand-transition>
v-show
の真偽値がtrueの場合は、div以下のコンポーネントが表示されて、falseの時は隠れるようになっている。パスワードの入力内容を見たり、隠したりする
<v-text-field label="パスワード" v-model="signupForm.password" @click:append="show = !show" ></v-text-field>
append
はボタンの配置を設定している<script> expprt default { data () { return { show: false } } } </script>例の如く、showの真偽値をボタンによって切り替えている。
showの真偽値によって、テキスト内容を見たり隠したりする
<v-text-field label="パスワード" v-model="signupForm.password" :type="show ? 'text' : 'password'" :append-icon="show ? 'mdi-eye' : 'mdi-eye-off'" @click:append="show = !show" ></v-text-field>
type
属性をshowによって紐づけ(bind)て、入力フォームのタイプを切り替えている
icon
もshowによって紐づけ(bind)て、アイコンの見た目を切り替えている
- 投稿日:2020-09-08T17:27:13+09:00
【Nuxt.js】Nuxt文法編:component①
? この記事はWP専用です
https://wp.me/pc9NHC-DX前置き
componentとは
使いまわしができる、
再利用ができるものです?シンプルなボタンでも
CSSが長くなったりして
まいかい書くのは面倒ですよね…?
それを解決してくれるのが
componentです?作り方、表示のさせ方を解説していきます✍️
目次
前置き
componentの種類と使用箇所
基本コード
Step1: 使い回すコンポーネントを作る
Step2: コンポーネントをインポートする
自動でインポートする
まとめcomponentの種類と使用箇所
種類
まずは種類を把握しましょう。
おおまかに全部で3つあります?
今回は1の自作のコンポーネント
について解説していきます?
前置きに書いたボタンのような場合は
自作のコンポーネントに該当します?♀️
- <好きに命名した名前 /> =自作のコンポーネント importが必要!
- layouts内でのみ使用
- ネストされたルート内で使用
nuxtとnuxt-childについては
別記事でご紹介します?使用箇所
componentsが使える場所
(インポートできる場所)は
ページを構成する部分です!・layout
・他のコンポーネント
・pageコンポーネント
自作のコンポーネントの場合は
この中のどれでも使用可能です?基本コード
基本コードがこちら。
あとは使いまわしたい物に
作り替えていきましょう?✨? 続きはWPでご覧ください?
https://wp.me/pc9NHC-DX
- 投稿日:2020-09-08T00:11:18+09:00
[Vue.js] 子コンポーネントのプロパティをそのまま全て使用する方法
この子コンポーネントのプロパティ、ほとんど全部そのまま使うんだけど、すべてひとつずつ書くのは冗長な気がする・・・
という疑問から、
- 子コンポーネント プロパティ 全部
- Vue プロパティ そのまま 使う
などでググってみましたが、意外と答えにたどり着くのに時間がかかってしまいました。
v-bind="$attrs"
を使うVue.component('base-input', { props: ['label', 'value'], template: ` <label> {{ label }} <input v-bind="$attrs" v-bind:value="value" v-on:input="$emit('input', $event.target.value)" > </label> ` })このようにすることで、input 要素が持つプロパティを base-input から全て使うことができます。
そもそもルート要素は全てのプロパティが親に継承される
下記の様に、ルート要素になっている要素のプロパティはそのまま親コンポーネントからアクセスすることができます。
Vue.component('base-input', { props: ['label', 'value'], template: ` <input v-bind:value="value" v-on:input="$emit('input', $event.target.value)" > ` })親にプロパティ継承させたくない場合は
inheritAttrs: false
先ほどの例の逆で、親にルート要素のプロパティ継承させたくない場合は
inheritAttrs: false
を使います。Vue.component('my-component', { inheritAttrs: false, // ... })
v-bind="$attrs"
とinheritAttrs: false
を併用することで、特定の要素のプロパティを親コンポーネントがそのまま使うことができます。Vue.component('base-input', { inheritAttrs: false, props: ['label', 'value'], template: ` <label> {{ label }} <input v-bind="$attrs" v-bind:value="value" v-on:input="$emit('input', $event.target.value)" > </label> ` })参考
- 投稿日:2020-09-08T00:00:40+09:00
【とりあえず動かしたい超初心者向け】はじめてのVue.js環境構築
はじめに
Javascriptのモダンフレームワーク周りに関する知見がほとんどない人にVue.jsの環境構築をレクチャーする機会があったので、この機に構築手順をまとめてみます。
30分1時間で最低限のツールと手順を把握しつつ環境構築することを目指したため、全体的に雑さが目立ちますがご了承ください。前提
コマンドラインツール(コマンドプロンプトとかターミナル)が使える
衝撃的だったのですが、レガシーな環境で開発されている場合、意外と基本操作を知らない方がいるようなので念のため。
今後登場するコマンドも、これを使って実行していきます。
開発を進める上で必須なので、よくわからない方はこちらから基本を学びましょう。
https://tutorial.djangogirls.org/ja/intro_to_command_line/筆者の実行環境 (参考までに)
Node: v12.13.1 npm: 6.12.1 yarn: 1.19.1 Vue-CLI: @vue/cli 4.1.1Vue.js
https://jp.vuejs.org/index.html
Vue.jsとは
- JavaScriptフレームワーク(フロントコーディングの処理の一部を自動化したり簡略化してくれるツール)の1つ
- 単一のページ(要は1つのhtmlファイル)でコンテンツを切り替えるシングルページアプリケーション(SPA)を実現できる
- 基本はJavaScriptだが、フレームワーク独自の書き方やルールが存在する
- 他のモダンフレームワークとしてはAngular, Reactなどが有名だが、これら2つと比べると軽量・簡単で学習コストが低いのが特徴で、比較的中小規模のプロジェクト向き
Node.js
Node.jsとは
- サーバサイドで動くJavaScriptの実行環境
- 今回はこれの一部機能を使うだけなので、詳細は割愛します
Nodeのインストール
Windows
こちらを参照
すみませんが、Windowsに関してはあまり詳しくないのでネット記事を参考にインストールしてみてください。
https://techacademy.jp/magazine/16050MacOS
こちらを参照
https://qiita.com/kyosuke5_20/items/c5f68fc9d89b84c0df09バージョンについて
2020/09/07現在、Nodeはv14.9.0が最新バージョンだが、公式サイトを見るとv12.18.3がLTS(推奨版)とのことなので、とりあえずわからなかったらこれをインストールすることをおすすめする。
https://nodejs.org/ja/download/
上記記事にも書いてあるが、以下で安定版をインストールできる。
nodebrew install-binary stablenpm
- npmは、Node.jsに含まれるパッケージ管理ツール
- パッケージ(JavaScriptのモジュールやライブラリ)をダウンロードからインストールまでよしなにやってくれる上に、依存関係(他にもこのライブラリがないと正常に動作しないよ、みたいな関係のもの)もいい感じにインストールして解決して読み込んで使える状態にしてくれる優れもの
- 現代のモダンフレームワークを用いた開発は大半がこれ(系)を使ってライブラリを管理している。
- Nodeをインストールした時点でこれもインストールされているため、特に追加操作はなし。
# バージョン確認 npm -vYarn
https://qiita.com/lelouch99v/items/c97ff951ca31298f3f24
- npmと同じ、JavaScriptのパッケージ管理ツール。
- npmより高速で何かと便利なので、入れておくとよいかもnpm i -g yarn yarn -vnpmとyarnの各種コマンド
こちらが参考になります
https://qiita.com/rubytomato@github/items/1696530bb9fd59aa28d8Vue-CLI
Vue-CLIとは
- Vue.jsの開発を手早く進めるためのシステム
- コマンド1つで、後は案内されるがままにオプションを選んでいけばいい感じのスタートアップ環境が作れる便利ツール
インストール
npm i -g @vue/cli # OR yarn global add @vue/cliプロジェクトの作成
カレントディレクトリにプロジェクトディレクトリが作成されるため、まずは場所を用意してください。
vue create vue-sample-project
? Please pick a preset:
と聞かれるので、Manually select features
を選択してください。
上下で移動、Enterで決定です。
次に入れる機能を聞かれますが、
Router
だけ追加してください。
上下で移動、Spaceで選択、Enterで決定です。
他にも色々聞かれますが、全部EnterでOKです。
しばらくするとプロジェクト作成が完了するので、プロジェクトディレクトリに移動しましょう。cd vue-sample-project
ローカルで実行
npm run serve # OR yarn serve
成功すると、デフォルトではhttp://localhost:8080/ にサーバが立ち上がるのでブラウザからアクセスしてください。
ここで、ページトップの
About
を押してみましょう。あたかも別のページに遷移したかのように見えたかと思いますが、同じページ(htmlファイル)の中でJavaScriptを使って内容を切り替えています。これを、ルーティングといいます。
これにより、ページ全体を読み込み直す必要がないため動作が軽くなると共に、ヘッダやフッタといった共通部品をより簡単に定義できるようになります。ビルド
npm run build # OR yarn build
成功すると、ルートディレクトリ直下に
dist
というフォルダが作成され、中にプロジェクトデータが出力されます。最低限知っておくべきディレクトリ構成
public
Vueシステムによっていい感じに包括処理されない、外側のエリア。
build時にそのまま出力される。
index.htmlもここにある。src > assets
imageとかsoundみたいなアセットを配置する。
src > components
共通ボタンのような、UIコンポーネント(ページの中に配置される部品)を配置する。
src > router
先ほど体験した、
About
押下時に表示されるページがどれか、というルーティング設定がここに定義されている。src > views
単一ページのコンポーネントを配置する。
ルーティングにより切り替えられるページがここに定義される。src > App.vue
エントリーポイントとなる大元のコンポーネント。
src > main.js
エントリーポイントとなる大元のスクリプトファイル
package.json
npm(yarn)の管理パッケージや
yarn serve
のようなアクションタスクが定義されている。最後に
擦られまくったネタな上にとんでもなく駆け足でしたが、以上になります。
この記事ではとりあえずプロジェクトをセットアップしてとにかく動かす所まで実施しましたが、細かい動作原理、コーディングにおけるVueの作法等には一切触れていないため、このまま開発に移るのは難しいと思います。Vueは公式サイトがかなり親切(しかも日本語対応)ですし、Qiitaをはじめとするリファレンスもかなり充実しています。
ハマりどころもよく見たら公式に書いてあったりすることが結構あるので、まずは公式を見てみて、よく分からなければQiitaとかで分かりやすい解説記事を探してみる、を繰り返していくことで、きっとツールの魅力に気付いていけるようになると思います。いざ、Vueのせかいへ!レッツゴー!