AWS Amplify Framework(3)Authenticationカテゴリ

Authenticationカテゴリ

Authenticationカテゴリは、認証(AuthN)と認可(AuthZ)の機能を提供する。AWS Cognito ユーザプール を介して、FacebookやGoogleなどのOpenIDプロバイダーの情報を含むユーザ情報を格納し、ユーザの認証を行う。また、AWS Cognito Federated Identitiesを介して、例えば、S3へのファイルアップロードできる権限を付与するなど、AWSリソースに対しての認可の機能も提供する。AWS CLIは、アクセス制御ポリシーの自動化と、GraphQLを用いたきめ細やかなアクセス制御機能を提供する。

シンプルな認証では、AWS Cognito ユーザプール を通してユーザの認証のみを行い、この認証に通れば、(ログイン)アプリが利用するAWSリソースと通信が可能となる。一方で、ユーザ別にコンテンツを出し分ける必要がある場合などには、そのユーザに関連するAWSリソースのみにアクセス権限を付与しなければならない。この場合は、AWS Cognito Federated Identitiesを通して、そのユーザに必要な権限のみを許可された、AWS Credentialがやりとりされる。

セットアップ

Amplifyプロジェクトのルートディレクトリでamplify add authコマンドを実行することで、ウィザードに従って自動セットアップを行うことができる。

設定内容の例はこちら。

設定項目 内容
リソース名 myproject
User Pool名 myproject
Sign-Inに使用する属性 Email
MFA 無効
ユーザ登録等にEメールを使用 有効
認証メールのタイトル MyProject から 認証コード をお送りします
認証メールの本文 あなたの認証コードは {####} です。
Sign-Up時に必須の属性 Email, Name
Tokenの有効期間 30日
アクセスできるユーザ属性の限定 なし
その他の機能 ホワイトリストによるEmailドメインのフィルタ
OAuthの使用 なし
Lambda Triggers Pre Sign-up
ホワイトリストに指定するドメイン surbiton.jp

上の内容を設定するために、以下のような対話式ウィザードによって必要事項を埋めていく。

$ amplify add auth

 Do you want to use the default authentication and security configuration? Manual configuration
 Select the authentication/authorization services that you want to use: User Sign-Up & Sign-In only (Best used with a cloud API only)
 Please provide a friendly name for your resource that will be used to label this category in the project: myproject
 Please provide a name for your user pool: myproject
 Warning: you will not be able to edit these selections. 
 How do you want users to be able to sign in? Email
 Multifactor authentication (MFA) user login options: OFF
 Email based user registration/forgot password: Enabled (Requires per-user email entry at registration)
 Please specify an email verification subject: MyProject から 認証コード をお送りします
 Please specify an email verification message: あなたの認証コードは {####} です。
 Do you want to override the default password policy for this User Pool? No
 Warning: you will not be able to edit these selections. 
 What attributes are required for signing up? Email, Name
 Specify the app's refresh token expiration period (in days): 30
 Do you want to specify the user attributes this app can read and write? No
 Do you want to enable any of the following capabilities? Email Domain Filtering (whitelist)
 Do you want to use an OAuth flow? No
 Do you want to configure Lambda Triggers for Cognito? Yes
 Which triggers do you want to enable for Cognito (Press <space> to select, <a> to toggle all, <i> to invert selection)Pre Sign-up
 What functionality do you want to use for Pre Sign-up (Press <space> to select, <a> to toggle all, <i> to invert selection)Sign-Up email filtering (whitelist)
 Enter a comma-delimited list of allowed email domains (example: 'mydomain.com, myotherdomain.com'). surbiton.jp
Succesfully added the Lambda function locally
 Press enter to continue 
Successfully added resource myproject locally

Lambdaトリガー

Amplify CLIを用いることで、ホワイトリスト内のユーザのみに新規登録を認める処理を加えるなど、AWS Cognito ユーザプール のトリガに対応したLambdaを設定することができる。

Vue Components

Authカテゴリに関連して使用できるVueのUI Componentsは以下の通り。

Components 内容
<amplify-authenticator></amplify-authenticator> 認証全般
<amplify-sign-in></amplify-sign-in> Sign-In
<amplify-confirm-sign-in></amplify-confirm-sign-in> Sign-Inの確認
<amplify-sign-up></amplify-sign-up> Sign-Up
<amplify-forgot-password></amplify-forgot-password> パスワード忘れ時
<amplify-sign-out></amplify-sign-out> Sign-Out
<amplify-set-mfa></amplify-set-mfa> MFAの設定

認証画面の例

認証カテゴリを組み込んだログイン画面の実装例は以下の通り。

<template> ブロック

認証コンポーネント の詳細は、Authentication Components を参照。

<template>
  <div id="authenticator">
    <div v-if="signInStatus === 'signedOut'">
      <!-- 認証全般のコンポーネント -->
      <amplify-authenticator v-bind:authConfig="authConfig"></amplify-authenticator>
    </div>
  </div>
</template>

<script> ブロック

currentauthenticateduserメソッド の詳細は、 Amplify JavaScript library – Auth Class を参照。

<script>
// aws-amplify ライブラリの Auth カテゴリをインポート
import { Auth } from 'aws-amplify'
// aws-amplify-vue ライブラリの AmplifyEventBus カテゴリをインポート (イベントの発行とリッスン)
import { AmplifyEventBus } from 'aws-amplify-vue'

export default {
  name: 'Authenticator',
  components: {},
  // Vue - Amplify Plugin - Authentication Components
  // https://aws-amplify.github.io/docs/js/vue#authentication-components
  data: function() {
    return {
      signInStatus: 'signedOut',
      authConfig: {
        // Eメールによるサインイン
        usernameAttributes: 'Email',
        signUpConfig: {
          // サインアップ時の項目を一旦全て非表示にする
          hideAllDefaults: true,
          // サインアップ時の項目
          signUpFields: [
            {
              label: 'Email',
              key: 'email',
              required: true,
              displayOrder: 1,
              type: 'string',
              signUpWith: true
            },
            {
              label: 'Name',
              key: 'name',
              required: true,
              displayOrder: 2,
              type: 'string'
            },
            {
              label: 'Password',
              key: 'password',
              required: true,
              displayOrder: 3,
              type: 'password'
            },
          ]
        }
      }
    }
  },
  async beforeCreate() {
    try {
      // Amplify JavaScript library - Auth Class
      // https://aws-amplify.github.io/amplify-js/api/classes/authclass.html#currentauthenticateduser
      // ログインステータスの取得
      await Auth.currentAuthenticatedUser()
      this.signInStatus = 'signedIn'
    } catch (err) {
      this.signInStatus = 'signedOut'
    }
    // Vue - Amplify Plugin - AmplifyEventBus
    // authStateイベント のリッスン
    // https://aws-amplify.github.io/docs/js/vue#amplifyeventbus
    AmplifyEventBus.$on('authState', info => {
      switch (info) {
        case 'signedIn':
          this.signInStatus = 'signedIn'
          break
        default:
          this.signInStatus = 'signedOut'
          break
      }
    });
  }
}

<style> ブロック

<style>
  #authenticator {
    margin: auto;
    width: 460px;
  }
</style>

それ以外の画面に認証処理を追加する例

未認証のユーザにはページを表示させないように、ログイン後に表示される画面に認証処理を追加する例はこちら。

<script> ブロック

beforeCreate() でログイン状態を取得する。

<script>
export default { 
  name: 'UserTable', 
  // 使用するコンポーネント 
  components: {}, 
  // データ 
  data () { 
    // 必ず初期値が必要 
    return { 
      signInStatus: 'signedOut'
    } 
  },
  async beforeCreate() { 
    try { 
      // Amplify JavaScript library - Auth Class
      // https://aws-amplify.github.io/amplify-js/api/classes/authclass.html#currentauthenticateduser
      // ログインステータスの取得
      await Auth.currentAuthenticatedUser() 
      this.signInStatus = 'signedIn' 
    } catch (err) { 
      this.signInStatus = 'signedOut' 
    } 
    AmplifyEventBus.$on('authState', info => { 
      switch (info) { 
        case 'signedIn': 
          this.signInStatus = 'signedIn' 
          break 
        default: 
          this.signInStatus = 'signedOut' 
          break 
      } 
    }); 
  }
}
</script>

ローカライズ

標準の認証コンポーネントは、全て英語でメッセージが表示される。これらを 日本語対応 するためには、Amplifyの I18n カテゴリを使用して、main.js に以下の内容を追記する必要がある。

// 多言語対応
let languageDict = {
  ja:{
      // タイトル
      'Sign in to your account' : 'サインイン',
      'Create a new account': 'アカウントの新規作成',
      'Reset your password': 'パスワードをリセット',
      'Confirm Sign Up': 'メールアドレスの認証',
      // 入力項目
      'Username' : '会社のメールアドレス',
      'Email' : '会社のメールアドレス',
      'Enter your Email' : 'メールアドレスを入力してください',
      'Name' : '名前',
      'Password' : 'パスワード',
      'Enter your password' : 'パスワードを入力してください',
      'Code': '認証コード',
      'New Password': '新しいパスワード',
      'Confirmation Code': '認証コード',
      // 注釈
      'Forget your password? ' : 'パスワードを忘れた場合は ',
      'No account? ' : 'アカウントの作成は ',
      'Have an account? ': 'サインインは ', 
      'Lost your code? ': 'メールアドレスに認証コードが届きませんか? ', 
      // ボタン
      'Back to Sign In': 'サインイン',
      'Resend Code': '認証コードを再送信する',
      'Reset password' : 'パスワードを再設定',
      'Sign in' : 'こちら',
      'Sign In' : 'サインイン',
      'Sign Out' : 'サインアウト',
      'Create account' : 'こちら',
      'Create Account' : 'アカウントを作成',
      'Send Code': '次へ進む',
      'Submit': '送信',
      'Confirm': '登録完了',
      // エラーコード
      'Username cannot be empty': 'メールアドレスを入力してください',
      'null failed with error Generate callenges lambda cannot be called..': 'パスワードを入力してください',
      'Incorrect username or password.': 'メールアドレス もしくは パスワードが正しくありません',
      'Username/client id combination not found.': 'メールアドレスが正しくありません',
      'Invalid verification code provided, please try again.': '認証コードが正しくありません',
      'Password reset required for the user': 'パスワードを再設定してください'
  }
}
AmplifyModules.I18n.putVocabularies(languageDict)

Vue.js(2)コンポーネント

Vueコンポーネント

Vue.jsでは、名前付き再利用可能なVueインスタンスとして、Vueコンポーネントという仕組みが用意されており、HTMLの要素やスタイル、状態、挙動などを使いまわせる部品としてまとめて定義できる。Vue.component()という関数が用意されており、第一引数にVueインスタンス内に存在する要素名=コンポーネント名)を、第二引数にオプションを与える。

コンポーネント名は、kebab caseでもcamel caseでもどちらで命名しても構わないが、DOM内ではkebab caseでしか記述できないことを考慮すると、kebab caseに統一しておくことが望ましい。

<ul id="app">
  <list-item></list-item>
  <list-item></list-item>
  <list-item></list-item>
</ul>

<script>
Vue.component('list-item',{
  template: '<li>item</li>'
})
new Vue({
  el: '#app'
})
</script>

Vueコンポーネントで指定できるオプションは、以下の通り。

名前 内容
data UIの状態とデータ
filters データの整形
methods イベント時の挙動
computed データから派生して算出する値
template コンポーネントのテンプレート
props 親要素から子要素へのデータ受け渡し

コンポーネントは、グローバルのVue.jsに対して定義するグローバルコンポーネントと、あるVueインスタンスの中のみで使用できるローカルコンポーネントが存在する。ローカルコンポーネントは、対象のVueインスタンス内で定義する。

コンポーネントテンプレート

text/x-template

template内の要素をscriptタグ内で定義する方法

<script type="text/x-template" id="list-item">
  <li>item</li>
</script>

renderオプション

コンポーネント内でコードを用いる場合は、renderオプションを使用する。

単一ファイルコンポーネント

.vue拡張子の単一ファイル上でコンポーネントを実装することができる。これらのファイルを利用するときは、Webpackなどによるプリコンパイルが必要となる。また、Vueインスタンス内のcomponentsオプションにて、利用するコンポーネントを指定する必要がある。

下記のように、単一ファイルコンポーネント内でも他のコンポーネントをローカル登録することが可能である。

import ComponentA from './ComponentA'

export default {
  components: {
    ComponentA
  }
}

コンポーネントデータ

コンポーネント内のdataオブジェクトにそのままデータを記載すると、コンポーネントの全てのインスタンスでこれらのデータが共有されてしまう。これを防ぐために、コンポーネントでdataオブジェクトを使用する際には、関数を用いて値を返却する実装とする

コンポーネント間の通信

Vue.jsでは、各コンポーネント内で独自のスコープを持つので、基本的にはコンポーネントを跨いだデータの受け渡しはできないが、親コンポーネントと子コンポーネントの間では、データの受け渡しが可能である。親から子へはpropsオプションを用いて子から親にはイベントを用いてデータを受け渡す。

propsオプションは子コンポーネント内に記載し、受け渡されるデータの属性名や型などを指定することができる。親コンポーネントでは、v-bindを用いて受け渡す値を指定する。

コンポーネント 値の指定方法 値の命名規則
親コンポーネント v-bind:受け渡す値の名前=’コンポーネント内の値の名称’ kebab case
子コンポーネント props: {受け取る値の名前: {}} camel case

子コンポーネントから親コンポーネントへの通信は、カスタムイベントを使用する。イベントのリッスンには $on(eventName) を、イベントトリガには、 $emit(eventName) を使用する。

Vue.js(1)Vue.jsの概要

Vue.jsの特徴

Vue.jsは、ビューだけを取り扱うシンプルなライブラリで、DOM要素にバインディング指定することで、データ変更を検出する度に、DOM要素が表示内容を自動で更新する「リアクティブなデータバインディング」を提供する。したがって、値を都度算出したり、その値を設定するコードが不要。また反対に、ユーザからの入力を検出する度にJavascriptのデータを更新することもできる。

Vue.jsは、フレームワークはどんな規模でも段階的に柔軟に使えるべきであるという、ブログレッシブフレームワークの思想を基に開発されており、ライブラリを導入するなどすることで、規模や要求に応じた対応が可能である。

またVue.jsは、HTMLライク(HTML, CSS, Javascript)なコンポーネント単一ファイルに記述できるために非常に学習コストが低い。

Vue.jsの基本

Vue.jsは、イベントと要素との間に状態(State)を持つために、イベントとDOMとの関係を分けて考えることが可能である。UIの状態を担うJavascriptオブジェクトを中心に据え、

  • UIの状態とJavascriptオブジェクト
  • UIの状態とDOMツリー
  • イベントと状態の変更

の3つの視点からコンテンツを制作できる。

Vue.jsの構成

Vueオブジェクト

グローバル変数Vueは、コンストラクタモジュールの2つの役割を持つ。コンストラクタに指定する オプションオブジェクト は、以下のプロパティを指定することができる。

名前 内容
data UIの状態とデータ
el Vueインスタンスをマウントする要素
filters データの整形
methods イベント時の挙動
computed データから派生して算出する値

elプロパティ もしくは mountメソッド を用いて、マウント対象の要素を指定する。Vueの影響範囲は、このマウントした要素とその子要素に限られる

var vm = new Vue({
  el: '#app'
})
var vm = new Vue({
})
vm.$mount('#app')

また、これらのプロパティにアクセスするためのインスタンスプロパティが用意されている。詳細は、vue インスタンスプロパティを参照のこと。

インスタンスプロパティの例 内容
vm.$data データオブジェクト
vm.$props プロパティオブジェクト
vm.$el ルートDOM

UIデータの定義

dataプロパティを用いて、データのオブジェクトを指定する。dataプロパティで規定したデータは、更新毎に表示も変化する。この値をHTML上に反映させるためには以下のように記述する。なお、Vueインスタンスの変数名は、ViewModelの略として、慣例的にvmをよく使用する。

var vm = new Vue({
  el: '#app'
  data: {
    key: 'value'
  }
})
<div id="app">
  <p>{{ key }}</p>x
</div>

なお、 {{ key }} は、データをHTMLではなくプレーンテキストとして扱うため、HTMLとして出力する必要がある場合には、 v-html ディレクティブを使用する。また、dataプロパティにはデータのみを置き、値の処理を行う関数などは、methodsプロパティcomputedプロパティに記載する。

$watchメソッドは、Vueインスタンスの変更を検知し動作を開始するため、デバッグ等に利用できる。第一引数に監視対象の値第二引数に値が変更した際に事項する処理内容を規定します。

vm.$watch(function(){
  return this.key
},function(){
}

テンプレート

Vue.jsは、データとDOMツリーの関係を定義するテンプレート機能を提供しており、Mustache記法によるデータ展開ディレクティブによるHTML要素の拡張を行うことができる。dataプロパティのデータ だけでなく、 Computed, Method, Filterで定義した関数名 を指定することができる。

詳細は、テンプレート構文 – Vue.jsを参照のこと。

データ展開

v-bindを利用して、属性プロパティに値を適用することができる。

v-bind:属性名="dataのkey"

文字列だけではなく真偽値を適用して、表示を変更することもできる。また、属性名を角括弧で囲うことで、属性名を変数名として定義することもできる

<div id="app">
  <button v-bind:[attribuiteName]="key">button</button>
</div>
<script>
var attributeName = 'title'
var vm = new Vue({
  el: '#app',
  data: {
    key: 'value'
  }
})
</script>

v-bind:class に配列を渡すこともできる。

<div v-vind:class="[activClass, errorClass"]></div>

フィルタ

filtersプロパティは、テキストのフォーマット処理を行うことができる。関数として定義し、関数名がフィルタ処理後の変数名となる。{{ 値|フィルタ名 }}と記述することで、指定した値にフィルタを適用できる。

<div id="app">
  <p>{{ filteredKey|keyFilter }}</>
</div>
<script>
var vm = new Vue({
  el: '#app',
  data: {
    key: 'value'
  },
  filters: {
    keyFilter: function(){
    }
  }
})
</script>

複数のフィルタを | で連結することもできる。

算出プロパティ

computedプロパティは、派生したデータをプロパティとして公開する仕組みで、データに処理を加えたいときに使用する。 this を用いることで、 Vueインスタンス内の各種プロパティにアクセス できる。

詳細は、算出プロパティとウォッチャ – Vue.jsを参照のこと。

<div id="app">
  <p>{{ computedValue }}</>
</div>
<script>
var vm = new Vue({
  el: '#app',
  data: {
    key: 'value'
  },
  computed: {
    computedValue: function(){
        return this.key+100
    }
  }
})
</script>

算出プロパティも依存しちえるデータが更新されれば、自動的に更新される。算出プロパティは、算出対象の変数などの依存関係が更新されたときのみ再実行されるのに対して、メソッドは、再描画が発生する度に実行される

算出プロパティは、通常getterのみ提供されているが、別途setterを定義することもできる。

ディレクティブ

HTMLに対してディレクティブと呼ばれる独自の属性を追加し、DOMの操作を行うことができる。

条件付きレンダリング

v-ifおよびv-showディレクティブを用いて、これらの属性に真偽値を適用することで、要素の表示非表示を制御することができる。v-ifはDOMの追加削除自体を行うが、v-showはdisplayプロパティの変更を行って表示非表示を行う。頻繁に表示非表示が変更される場合は、v-showを使うほうがレンダリングコストが低い。

v-ifディレクティブと同時に、v-else-ifディレクティブv-elseディレクティブを使用することもできる。これらのディレクティブを使用した場合、再利用が可能な要素は描画されずにそのまま利用される。明示的に再描画を行う場合には、Key属性を追加して、Vueに別要素として認識させる必要がある

データ変更時の更新は行わずに展開を1度のみ行う場合は、v-onceディレクティブを使用することもできる。

詳細は、条件付きレンダリング – Vue.jsを参照のこと。

<div id="app">
  <p v-if="isShown">text</>
</div>
<script>
var vm = new Vue({
  el: '#app',
  computed: {
    isShown: function(){
        return true;
    }
  }
})
</script>

クラスとスタイルのバインディング

特定の条件を満たしているときにUIを変更する場合は、v-bindディレクティブを使用する。

また、v-bind:classは、指定された値のうち真のプロパティのみ、Classの属性値に反映する。下の例では、isShownは真のときのみ、error属性がClass属性に反映する。

<div id="app">
  <p v-bind:class="(error: isShown)">text</>
</div>
<script>
var vm = new Vue({
  el: '#app',
  computed: {
    isShown: function(){
        return true;
    }
  }
})
</script>

v-bind:styleは、スタイルプロパティとして要素に反映される。v-bind:属性名は、:属性名と省略して記述することもできる。

詳細は、クラスとスタイルのバインディング – Vue.jsを参照のこと。

リストレンダリング

v-forディレクティブを用いることで、配列もしくはオブジェクトデータを繰り返して表示できる。v-forは、v-bindと共に使用して、v-bindで一意なキーを与えなければならない

v-for="要素 in 配列"

また、v-forディレクティブは、オブジェクトのプロパティに対しても使用することができる。このとき、オブジェクトの値(Value)だけでなく、キー(key)およびインデックス(index)を指定することもできる

<ul id="v-for-object" class="demo">
  <div v-for="(value, name, index) in object">
    {{ index }}. {{ name }}: {{ value }}
  </div>
</ul>
new Vue({
  el: '#v-for-object',
  data: {
    object: {
      title: 'How to do lists in Vue',
      author: 'Jane Doe',
      publishedAt: '2016-04-10'
    }
  }
})

リスト要素に対する画面更新を行うために、push(), pop(), shift(), unshift(), splice(), sort(), reverse()などの変更メソッドがあらかじめ用意されている。

詳細は、リストレンダリング – Vue.jsを参照のこと。

イベントハンドリング

v-onディレクティブを持ちることで、イベントの発生の検知と検知時の実行する動作を記述することができる。v-on:イベント名は、@イベント名と省略して記述することもできる。

v-on:イベント名="式として実行したい属性名"

また、v-onディレクティブとv-bindディレクティブを、v-modelディレクティブとして記述することもできる。これは、DOMで変更があった場合に、その値をVueに反映できるディレクティブである。

<div id="app">
  <input type="number" v-model="key">
</div>
<script>
var vm = new Vue({
  el: '#app',
  data: {
    key: 'value'
  }
})
</script>

詳細は、イベントハンドリング – Vue.jsを参照のこと。

ライフサイクルフック

Vueにはライフサイクルが規定されていて、それぞれの状態に変化した際に、ライフサイクルフックを用いて処理を実行することができる。

  • beforeCreate
  • created
  • beforeMount
  • mounted
  • beforeUpdate
  • updated
  • beforeDestroy
  • destroy

詳細は、ライフサイクルダイアグラム – Vue.jsを参照のこと。

メソッド

methodsディレクティブを用いることで、Vue内のメソッドを定義することができる。v-onディレクティブにメソッド名を指定して、ボタンクリック等のイベント時に処理をするなどが考えられる。メソッド等を定義する際に記述する function(){ は省略できる

イベント修飾子

メソッドには、 呼び出し元からeventオブジェクトが渡される。eventオブジェクトが持つ preventDefault()stopPropagation() を用いることで、イベントを停止したりイベントの伝搬を停止することができる。

ただし、これらのメソッドを使用することで複雑な処理となることを避けるために、イベント修飾子を提供している。

イベント修飾子 動作
.stop イベントの伝搬を停止する
.prevent ページリロードの停止
.capture
.self event.targetが自分自身の場合のみ呼び出し
.once
.passive

キー修飾子

キーボードイベントをサブスクライブするにあたって、処理を容易にするために、キー修飾子も用意されている。

詳細は、イベントハンドリング – Vue.jsを参照のこと。