20200908のvue.jsに関する記事は8件です。

axiosをグローバルに呼び出す

設定する

src/main.js
import 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 で呼び出せます

おしまい

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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 のガイドを参照してください。

既にリリースしていてこの機能を使っているなら変更する手間がかなり大きいですが、動的テンプレートを生成しないようにしておくのもいいかなと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AppServiceで.NetCore Identity認証をするとnoscriptのHttpが返ってくる

現象

AppServiceに公開しているVue.jsで作成したWebアプリで.NetCoreIdentityによる認証を行っているが、
認証に失敗した場合に、responseとしてnoscriptタグが記載してあるHttpが返ってくる。
(ローカルでは正しく判定される)

作りとしては単純で、vue-routerのbeforeEachでバックエンドへ認証の問い合わせを行い、失敗したらログイン画面に遷移させるというコード

index.js
    router.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.cs
        public 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;
                    };
               });
        }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vueでコンポーネントの外側をクリックしたら閉じたい

dependencies

vue: 2.x

目的

コンポーネントの外側、または他の部分をクリックしたら、そのコンポーネントを非表示にしたい。

ModalやDialogのようなコンポーネントはscrim(黒い背景のこと)を持つため、外側をクリックしたら閉じるという動きを作りやすい。実際scrimはコンポーネント内ですし。

そうではなく、Popupなどの軽率にフロートしてなおかつ外側をクリックしたら閉じてほしい、というコンポーネントはそれぞれがdocument.onclickに反応する必要がある。

ググってみたら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>

解説

beforeMountbeforeDestroyはサーバーサイドレンダリングでは呼ばれない。
そのため、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には表示されるので、スタイルは好きに変更すれば良いのでは。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【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)て、アイコンの見た目を切り替えている

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Nuxt.js】Nuxt文法編:component①

? この記事はWP専用です
https://wp.me/pc9NHC-DX

前置き

componentとは
使いまわしができる、
再利用ができるものです?

button.gif

シンプルなボタンでも
CSSが長くなったりして
まいかい書くのは面倒ですよね…?
それを解決してくれるのが
componentです?

作り方、表示のさせ方を解説していきます✍️

目次

前置き
componentの種類と使用箇所
基本コード
Step1: 使い回すコンポーネントを作る
Step2: コンポーネントをインポートする
自動でインポートする
まとめ

componentの種類と使用箇所

種類

まずは種類を把握しましょう。
おおまかに全部で3つあります?
今回は1の自作のコンポーネント
について解説していきます?
前置きに書いたボタンのような場合は
自作のコンポーネントに該当します?‍♀️

  1. <好きに命名した名前 />  =自作のコンポーネント  importが必要!
  2.  layouts内でのみ使用
  3.  ネストされたルート内で使用

nuxtとnuxt-childについては
別記事でご紹介します?

使用箇所

componentsが使える場所
(インポートできる場所)は
ページを構成する部分です!

・layout
・他のコンポーネント
・pageコンポーネント
自作のコンポーネントの場合は
この中のどれでも使用可能です?

基本コード

基本コードがこちら。
あとは使いまわしたい物に
作り替えていきましょう?✨

? 続きはWPでご覧ください?
https://wp.me/pc9NHC-DX

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[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>
  `
})

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【とりあえず動かしたい超初心者向け】はじめての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.1

Vue.js

https://jp.vuejs.org/index.html

Vue.jsとは

  • JavaScriptフレームワーク(フロントコーディングの処理の一部を自動化したり簡略化してくれるツール)の1つ
  • 単一のページ(要は1つのhtmlファイル)でコンテンツを切り替えるシングルページアプリケーション(SPA)を実現できる
  • 基本はJavaScriptだが、フレームワーク独自の書き方やルールが存在する
  • 他のモダンフレームワークとしてはAngular, Reactなどが有名だが、これら2つと比べると軽量・簡単で学習コストが低いのが特徴で、比較的中小規模のプロジェクト向き

Node.js

https://nodejs.org/ja/

Node.jsとは

  • サーバサイドで動くJavaScriptの実行環境
  • 今回はこれの一部機能を使うだけなので、詳細は割愛します

Nodeのインストール

Windows

こちらを参照
すみませんが、Windowsに関してはあまり詳しくないのでネット記事を参考にインストールしてみてください。
https://techacademy.jp/magazine/16050

MacOS

こちらを参照
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 stable

npm

  • npmは、Node.jsに含まれるパッケージ管理ツール
  • パッケージ(JavaScriptのモジュールやライブラリ)をダウンロードからインストールまでよしなにやってくれる上に、依存関係(他にもこのライブラリがないと正常に動作しないよ、みたいな関係のもの)もいい感じにインストールして解決して読み込んで使える状態にしてくれる優れもの
  • 現代のモダンフレームワークを用いた開発は大半がこれ(系)を使ってライブラリを管理している。
  • Nodeをインストールした時点でこれもインストールされているため、特に追加操作はなし。
# バージョン確認
npm -v

Yarn

https://qiita.com/lelouch99v/items/c97ff951ca31298f3f24
- npmと同じ、JavaScriptのパッケージ管理ツール。
- npmより高速で何かと便利なので、入れておくとよいかも

npm i -g yarn
yarn -v

npmとyarnの各種コマンド

こちらが参考になります
https://qiita.com/rubytomato@github/items/1696530bb9fd59aa28d8

Vue-CLI

https://cli.vuejs.org/

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で決定です。
スクリーンショット 2020-09-07 22.03.19.png

次に入れる機能を聞かれますが、Routerだけ追加してください。
上下で移動、Spaceで選択、Enterで決定です。
スクリーンショット 2020-09-07 22.07.48.png

他にも色々聞かれますが、全部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というフォルダが作成され、中にプロジェクトデータが出力されます。

最低限知っておくべきディレクトリ構成

スクリーンショット 2020-09-07 22.54.05.png

public

Vueシステムによっていい感じに包括処理されない、外側のエリア。
build時にそのまま出力される。
index.htmlもここにある。

src > assets

imageとかsoundみたいなアセットを配置する。

src > components

共通ボタンのような、UIコンポーネント(ページの中に配置される部品)を配置する。

src > router

先ほど体験した、About押下時に表示されるページがどれか、というルーティング設定がここに定義されている。

src > views

単一ページのコンポーネントを配置する。
ルーティングにより切り替えられるページがここに定義される。

src > App.vue

エントリーポイントとなる大元のコンポーネント。

大雑把な各コンポーネント構成のイメージは以下
スクリーンショット 2020-09-07 22.57.54.png

src > main.js

エントリーポイントとなる大元のスクリプトファイル

package.json

npm(yarn)の管理パッケージやyarn serveのようなアクションタスクが定義されている。

最後に

擦られまくったネタな上にとんでもなく駆け足でしたが、以上になります。
この記事ではとりあえずプロジェクトをセットアップしてとにかく動かす所まで実施しましたが、細かい動作原理、コーディングにおけるVueの作法等には一切触れていないため、このまま開発に移るのは難しいと思います。

Vueは公式サイトがかなり親切(しかも日本語対応)ですし、Qiitaをはじめとするリファレンスもかなり充実しています。
ハマりどころもよく見たら公式に書いてあったりすることが結構あるので、まずは公式を見てみて、よく分からなければQiitaとかで分かりやすい解説記事を探してみる、を繰り返していくことで、きっとツールの魅力に気付いていけるようになると思います。

いざ、Vueのせかいへ!レッツゴー!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む