Amplify + Vue.js で認証機能付きの Web サイトを公開する

# はじめに
[**Amplify**](https://aws.amazon.com/jp/amplify/) は、簡単に Web サイトに機能を追加して公開できるサービスです。[**Vue.js**](https://jp.vuejs.org/) はフロントエンドアプリケーションを開発する際に用いられる JavaScript フレームワークです。本記事では Amplify を使って Vue.js アプリに認証機能を追加し、公開する方法を紹介します。

# 対象読者
- Amplify Framework の初心者の方
- Vue.js で作った Web サイトに Cognito の認証機能を付けたい方
- [【初心者向け】AWS Amplify Console + MkDocs で気軽に始める Web サイト公開(Qiita) ](https://qiita.com/yone_suke/items/ac1b99df926493e0fa13)を読まれた方

# 簡単用語説明
- [AWS Amplify](https://aws.amazon.com/jp/amplify/)
  - AWS を使用したサーバーレスな Web およびモバイルアプリ開発のためのフレームワークです。
  - CLI 、Framework 、Console の 3 つの要素で構成されています。( 詳細は下記 AWS 公式ブログをご参照ください。)
  - CLI … コマンドラインから AWS のバックエンドを構築できるインターフェイスです。
  - Framework … AWS バックエンドと連携しやすくするための各種ライブラリです。
  - Console … 静的サイトのホスティング、CI/CD の運用を自動化するマネージドサービスです
  - 参照：[スタートアップが AWS Amplify を使うべき3つの理由](https://aws.amazon.com/jp/blogs/startup/techblog-3reasons-amplify/)

- [AWS Cognito](https://aws.amazon.com/jp/cognito/)
  - ウェブアプリケーションやモバイルアプリケーションの認証、許可、ユーザー管理機能を提供する AWS サービスです。
  - 同系統の他サービスとしては、[Firebase Authentication](https://firebase.google.com/docs/auth?hl=ja) や、[Auth0](https://auth0.com/jp/) などが挙げられます。
  - 同じく AWS サービスである Amplify と連携させやすいのが特徴です。
  - 参照：[はじめてのAWS Cognito！！](https://qiita.com/katekichi/items/dbf279077db6a7b597fc)

- [Vue.js](https://jp.vuejs.org/)
  - Web サイトのユーザーインターフェイスを構築するための JavaScript フレームワークです。
  - 同系統の他フレームワークとしては、 [React](https://ja.reactjs.org/) や、 [Angular](https://angular.io/) 、[Svelte](https://svelte.dev/) などが挙げられます。
  - 参照：[Vue.jsをはじめてみる #1 ~公式ガイドを読む編~](https://qiita.com/nayucolony/items/af28266c523b8fe0d67c)

# Amplify Console を使ったWeb サイト公開の方法 2つ
- **1. AWS マネジメントコンソール ( 以下、AWS M/C と略 ) から使う方法**
  - 主として GUI ( AWS M/C ) を利用する方法です。**Amplify 初心者向け。**
  - 詳細は、[以前の記事](https://qiita.com/yone_suke/items/ac1b99df926493e0fa13)で説明しています。

- **2. Amplify CLI から使う方法**
  - CUI ( Amplify CLI ) を利用する方法です。1. の方法で Amplify に慣れた方向け。
  - **本記事では、こちらの方法を紹介します。**

# 2. Amplify CLI から Amplify Console を使う方法
## 章の構成
- [2-1. Vue.js のセットアップ](#2-1-vuejs-のセットアップ)
  - Vue.js をインストールして、ローカル PC で実行する方法を紹介します。
- [2-2. Amplify CLI のセットアップ](#2-2-amplify-cli-のセットアップ)
  - Amplify CLI をインストールして、コマンド実行用 IAM ユーザーを設定する方法を紹介します。
- [2-3. Amplify アプリの新規作成](#2-3-amplify-アプリの新規作成)
  - Amplify アプリを新規作成する方法を紹介します。
- [2-4. Vue.js アプリをリリース](#2-4-vuejs-アプリをリリース)
  - 2-1. で作成した Vue.js アプリを Amplify Console にホスティングする方法を紹介します。
  - Amplify Console へのホスティングに Amplify CLI を利用します。
- [2-5. バックエンド側で認証機能の追加](#2-5-バックエンド側で認証機能の追加)
  - AWS バックエンドにユーザー認証基盤を構築する方法を紹介します。
- [2-6. フロントエンド側に認証画面を追加](#2-6-フロントエンド側に認証画面を追加)
  - Vue.js に Amplify Framework を組み込む方法を紹介します。
  - 実際にサインイン画面からサインインできるところまで確認します。
- [2-7. ユーザーのサインアップの制限](#2-7-ユーザーのサインアップの制限)
  - サインインできるユーザーを制限する方法を紹介します。
- [2-8. ブランチ自動検出設定を追加](#2-8-ブランチ自動検出設定を追加)
  - Amplify のブランチ自動検出設定を有効化する方法を紹介します。
  - Git ブランチが新規作成される際、自動で新規バックエンドも構築されるようになります。

## 各節の構成
- **前提**
  - 後段の「操作」を実施するにあたっての前提知識や、用意 / 登録するべきサービスを紹介しています。
  - 「操作」を実施する前に、ご一読されることをお勧めします。
- **操作**
  - 操作手順を、操作画面やコマンドプロンプトの実行コマンドを交えて紹介しています。
  - 実行コマンドは、基本的に Windows 10 上の Git Bash で実行した結果を表示しています。
- **結果**
  - 「操作」を実施した後に想定される結果を紹介しています。
  - 節の内容に応じて「結果」の後にオプションで項目を追加しています。

## 2-1. Vue.js のセットアップ
### 前提
- Vue.js の開発には、Vue CLI を使うと便利です。
  - 今回の Vue CLI インストール手順は、下記の記事を参照しました。
  - 参照：[Vue.js を vue-cli を使ってシンプルにはじめてみる](https://qiita.com/567000/items/dde495d6a8ad1c25fa43)
- Vue CLI は [Node.js](https://nodejs.org/ja/) 上で動きますので、Node.js をあらかじめインストールしておいてください。
  - Windows 版インストール ：[Node.js / npmをインストールする（for Windows）](https://qiita.com/taiponrock/items/9001ae194571feb63a5e)
  - Mac 版インストール：[MacにNode.jsをインストール](https://qiita.com/kyosuke5_20/items/c5f68fc9d89b84c0df09)

### 操作
- Vue CLI をインストールしてください。`-g`を付けてインストールするため、次回アプリ作成時はこの操作は不要です。

```
$ node -v  // Node.js がインストールされていることと、node のバージョンの確認
v12.13.0

$ npm -v  // npm のバージョンの確認
6.12.0

$ npm install -g @vue/cli  // Vue CLI のインストール

$ vue --version  // 正常にインストールされていることの確認
@vue/cli 4.2.2
```

- Vue CLI でアプリのプロジェクトを作成してください。

```
$ cd root-dir  // 下記コマンドを打つ際は、任意のディレクトリ配下で実施してください。
$ vue create tsproject  // 新規プロジェクトの作成

> dev (babel, typescript, pwa, router, vuex, eslint)  // この項目を選択してください。
  default (babel, eslint)
  Manually select features

$ cd tsproject  // 作成されたディレクトリに移動してください。

$ npm run serve   // ローカル PC 内で見れるようになります。

```

### 結果
- `http://localhost:8080/`に Web ブラウザでアクセスすると、Vue.js のサンプルページが表示されます。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518221/4ddc4d90-9304-23d3-4d45-cb1b924208d6.png)
- Vue Router の機能により、「About」を選択すると、`/about`ページへ遷移します。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518221/b7c76a0c-591d-9b01-a84e-5e33e0b74a93.png)

### 後続作業 ( Git リポジトリのセットアップ )
- 下記の記事の 1-2. と同様の操作を実施してください。
  - 参照：[【初心者向け】AWS Amplify Console + MkDocs で気軽に始める Web サイト公開](https://qiita.com/drafts/ac1b99df926493e0fa13/edit#1-2-git-%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%AE%E7%94%A8%E6%84%8F)
  - リポジトリ名は`amplifytsproject`で作成しました。
  - Vue CLI で新規アプリを作成すると、自動で最初の`git commit`まで実施されているので、後は`git remote add` と`git push -u origin master`だけコマンド実行しました。

## 2-2. Amplify CLI のセットアップ
### 前提
- 2-1. の「後続作業」まで完了した状態にしてください。
- Amplify CLI も、Node.js 上で動きます。インストール手順は下記記事を参照しました。
  - 参照：[AWS Amplify CLIの使い方〜インストールから初期セットアップまで〜](https://qiita.com/Junpei_Takagi/items/f2bc567761880471fd54)
- AWS アカウントを持っていない方は、下記を参照して用意してください。
  - 参照：[AWS アカウント作成の流れ(AWS公式)](https://aws.amazon.com/jp/register-flow/)
- Amplify CLI の初期セットアップ操作は、強い権限を持つ IAM ユーザー もしくは ルートユーザーで実施してください。
- 初期セットアップの結果、作成される IAM ユーザーはデフォルトで`AdministratorAccess`の権限が付与されます。
  - AWS アカウント内でのほとんど全ての操作が可能な強い権限を持つ IAM ユーザーが作成されますので、運用される際はお気を付けください。

### 操作
- Amplify CLI をインストールしてください。既に実施されている方は飛ばして問題ありません。

```
$ npm install -g @aws-amplify/cli  // Amplify CLI のインストール
$ amplify -v  // Amplify CLI がインストールされていることを確認
4.16.1
```

- Amplify CLI を初期セットアップしてください。既に実施されている方は飛ばして問題ありません。

```
$ amplify configure  // このコマンドを実行すると Web ブラウザが立ち上がり、AWS ログインページが表示されます。
Follow these steps to set up access to your AWS account:

Sign in to your AWS administrator account:
https://console.aws.amazon.com/
Press Enter to continue   // 「AdministratorAccess」などの強い権限を持っている IAM ユーザーで AWS ログイン後にまたこのコンソール画面に戻ってきて Enter を押します。

// AWS ログイン後、Enter 押下

Specify the AWS Region
? region:  ap-northeast-1  // ① 東京リージョンを選択しました。お好みのリージョンを選択してください。
Specify the username of the new IAM user:
? user name:  amplify-TVofWdlfkj  // ここで入力した値が IAM ユーザー名に使用されます。
Complete the user creation using the AWS console
https://console.aws.amazon.com/iam/home?region=undefined#/users$new?step=final&accessKey&userNames=amplify-TVofWdlfkj&permissionType=policies&policies=arn:aws:iam::aws:policy%2FAdministratorAccess
Press Enter to continue

// 再び Web 画面に移り、IAM ユーザーを作成するように促されます。基本的には全てデフォルトで「次のステップ」を選択すれば大丈夫です。
// 作成された IAM ユーザーの「アクセスキー ID 」、「シークレットアクセスキー」はこの後すぐに使いますのでコピーしておいてください。

// IAM ユーザー作成後、Enter 押下

Enter the access key of the newly created user:
? accessKeyId:  **********  // ② 作成した IAM ユーザーの「アクセスキー ID 」を入力してください。
? secretAccessKey:  ******************** // ③ 作成した IAM ユーザーの「シークレットアクセスキー」を入力してください。
This would update/create the AWS Profile in your local machine
? Profile Name:  tsproject  // ④ 任意のプロファイル名を指定してください。

Successfully set up the new user.  // この表示が最後に表示されれば初期セットアップクリアです。
```

### 結果
- `%UserProfile%\.aws`配下の`config`ファイルと`credentials`ファイルにプロファイル設定が追記されます。( もしこれらのファイルが存在しなければ、新規作成されます。)

```
// %UserProfile%\.aws\config の内容
[default]
… ( 略 ) …
[profile tsproject]    // 操作の中の④で指定したプロファイル名が指定されている。
region=ap-northeast-1  // 操作の中の①で指定したリージョンが入力されている。

// %UserProfile%\.aws\credentials の内容
[default]
… ( 略 ) …
[tsproject]            // 操作の中の④で指定したプロファイル名が指定されている。
aws_access_key_id=「アクセスキー ID 」 // 操作の中の②で指定したアクセスキー ID が指定されている。
aws_secret_access_key=「シークレットアクセスキー」  // 操作の中の③で指定したシークレットアクセスキーが指定されている。
```

## 2-3. Amplify アプリの新規作成
### 前提
- 2-2. まで完了した状態にしてください。

### 操作
- `amplify init`で、アプリを初期化してください。

```
$ cd tsproject    // 2-2. と同一のディレクトリ配下で、`amplify init`を実行してください。
$ amplify init
Note: It is recommended to run this command from the root of your app directory
? Enter a name for the project tsproject  // ①アプリのプロジェクト名を指定
? Enter a name for the environment prod   // ②バックエンドの環境名を指定

? Choose your default editor: Visual Studio Code  // デフォルト
> Visual Studio Code
  Atom Editor
  Sublime Text
  IntelliJ IDEA
  Vim (via Terminal, Mac OS only)
  Emacs (via Terminal, Mac OS only)
  None

? Choose the type of app that you're building javascript  // デフォルト
  android
  ios
> javascript

Please tell us about your project
? What javascript framework are you using vue  // デフォルト
  angular
  ember
  ionic
  react
  react-native
> vue
  none

? Source Directory Path:  src  // デフォルト
? Distribution Directory Path: dist  // デフォルト
? Build Command:  npm.cmd run-script build  // デフォルト
? Start Command: npm.cmd run-script serve  // デフォルト
Using default provider  awscloudformation  // CloudFormationが裏で実行されています。
… ( 中略 ) … 
Your project has been successfully initialized and connected to the cloud!  // CloudFormation の実行が成功しました。
… ( 中略 ) … 
```

### 結果
- プロジェクトフォルダ内に`amplify`フォルダが作成されます。

```
$ tree -a amplify/
tsproject/amplify/
|-- #current-cloud-backend   // ③ S3にアップロードされるディレクトリ
|   `-- amplify-meta.json    // ④ S3にアップロードされるファイル
|-- .config
|   |-- local-aws-info.json
|   |-- local-env-info.json
|   `-- project-config.json
|-- backend
|   |-- amplify-meta.json
|   `-- backend-config.json
`-- team-provider-info.json
```

- Amplify のサービス画面で、新規アプリが作成されていることが確認できます。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518221/f9c9e521-fb0e-2fb9-1219-b42c4cc494d4.png)

- CloudFormation のサービス画面で、新規スタックが作成されていることが確認できます。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518221/6b847494-1254-63fa-b05a-61a772e4d39b.png)

- S3 のサービス画面で、新規バケット内にプロジェクト関係ファイル(③、④)がアップロードされていることが確認できます。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518221/afd5cb95-8522-0ea3-99ee-8c937125d1e8.png)

## 2-4. Vue.js アプリをリリース
### 前提
- 2-3. まで完了した状態にしてください。

### 操作
- `amplify hosting add`で、アプリをホスティングしてください。

```
$ amplify hosting add
? Select the plugin module to execute (Use arrow keys)
> Hosting with Amplify Console (Managed hosting with custom domains, Continuous deployment)
  Amazon CloudFront and S3

? Choose a type
> Continuous deployment (Git-based deployments)
  Manual deployment
  Learn more

? Continuous deployment is configured in the Amplify Console. Please hit enter once you connect your repository

// Web ブラウザで Amplify サービス画面が表示される。
```

- Amplify サービス画面で下記のように操作してください。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518221/0277b424-f1e5-c3e0-91e3-ebd7a69f39c6.png)

- コンソール画面に戻り、Enter を押下してください。

```
? Continuous deployment is configured in the Amplify Console. Please hit enter once you connect your repository

// Enter を押下する

Amplify hosting urls:
┌──────────────┬──────────────────────────────────────────────┐
│ FrontEnd Env │ Domain                                       │
├──────────────┼──────────────────────────────────────────────┤
│ master       │ https://master.＜App ID＞.amplifyapp.com     │
└──────────────┴──────────────────────────────────────────────┘
```

### 結果
- Amplify サービス画面のフロントエンド環境がリリースされています。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518221/c815721a-9afb-f7ea-419a-82ed0b282b4c.png)

- `https://master.＜App ID＞.amplifyapp.com `でアクセスすると、2-1. の結果と同じ画面 ( Vue.js のサンプルページ ) が表示されます。![amplify+vue.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518221/4d874064-2f9a-fc5c-8015-c16df40dff07.jpeg)



- `amplify status`で現在のバックエンドのデプロイ状況を確認できます。

```
$ amplify status

Current Environment: prod

| Category | Resource name  | Operation | Provider plugin |
| -------- | -------------- | --------- | --------------- |
| Hosting  | amplifyhosting | No Change |                 |  // Hosting が追加されています。


Amplify hosting urls:
┌──────────────┬──────────────────────────────────────────────┐
│ FrontEnd Env │ Domain                                       │
├──────────────┼──────────────────────────────────────────────┤
│ master       │ https://master.＜App ID＞.amplifyapp.com     │  // 公開されている URL が表示されています。
└──────────────┴──────────────────────────────────────────────┘
```

### 参考
- 2-4. の結果の時の CloudFormation の状態は、2-3. の結果の時と変わりません。
  - 2-4. では 新規の CloudFront ディストリビューションも、新規の S3 バケットも作成されません。
  - 私見ですが、ビルドされたコンテンツは AWS が管理する CloudFront、S3 から公開されているようです。
  - **CloudFront、S3 の細かい設定を変更する要件がある場合は、`amplify hosting add`を実行する際`Hosting with Amplify Console`ではなく`Amazon CloudFront and S3`を選択するべきと思われます。**

## 2-5. バックエンド側で認証機能の追加
### 前提
- 2-4. まで完了した状態にしてください。

### 操作
- `amplify add auth`で、バックエンドに認証機能を追加してください。

```
$ amplify add auth
> Default configuration    // デフォルト
  Default configuration with Social Provider (Federation)
  Manual configuration
  I want to learn more.

 Warning: you will not be able to edit these selections.
 How do you want users to be able to sign in?
  Username
> Email      // Email を選択
  Phone Number
  Email and Phone Number
  I want to learn more.

 Do you want to configure advanced settings? (Use arrow keys)
> No, I am done.    // デフォルト
  Yes, I want to make some additional changes.
```
- ローカルの設定を`amplify push`でクラウドに反映させてください。

```
$ amplify push
√ Successfully pulled backend environment prod from the cloud.

Current Environment: prod

| Category | Resource name     | Operation | Provider plugin   |
| -------- | ----------------- | --------- | ----------------- |
| Auth     | tsproject1cc0f2f5 | Create    | awscloudformation |
| Hosting  | amplifyhosting    | No Change |                   |
? Are you sure you want to continue? Yes
/ Updating resources in the cloud. This may take a few minutes...
… ( 中略 ) …
√ All resources are updated in the cloud
```

### 結果
- Amplify サービス画面で`Authentication`が追加されていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518221/edc5c79e-de4c-5c85-9ee0-94a58513bc09.png)
- CloudFormation サービス画面でネステッドスタックが作成されていることが確認できます。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518221/2cf7c809-263a-a906-6757-c8a53c7bc726.png)


## 2-6. フロントエンド側に認証画面を追加
バックエンドの認証基盤をフロントエンドから利用できるように修正します。
### 前提
- 2-5. まで完了した状態にしてください。
- TypeScript の設定を追加した Vue.js プロジェクトでは`aws-amplify`をインストールして実行するとエラーが出力されるため、下記を参照してエラーを修正しました。
  - 参照：[Vue CLI 3でAWS Amplify + TypeScriptでビルド時のエラー解消](https://qiita.com/YoshinoriSatoh/items/470eb31a587ba0dc8f99)

### 操作
- `aws-amplify`と`aws-amplify-vue`をインストールしてください。

```
npm install aws-amplify aws-amplify-vue
```

- `main.ts`を下記のように修正してください。

```typescript(main.ts)
import Vue from 'vue'
import App from './App.vue'
import './registerServiceWorker'
import router from './router'
import store from './store'
// ---------------↓ここから追記↓---------------
import Amplify, * as AmplifyModules from 'aws-amplify'
// @ts-ignore
import { AmplifyPlugin } from 'aws-amplify-vue'
// @ts-ignore
import aws_exports from './aws-exports'
Amplify.configure(aws_exports)

Vue.use(AmplifyPlugin, AmplifyModules)
// ---------------↑ここまで追記↑---------------
Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')
```

- `tsconfig.json`を下記のように修正してください。

```json(tsconfig.json)
// … ( 以上略 ) … 
    "types": [
      "webpack-env",
      "node"    // 追記
    ],
// … ( 以下略 ) …
```

- モジュールが足りない旨のエラーが出る場合、下記を実行してモジュールを追加してください。
  - 私は`zen-observable`が足りていない旨のエラーが出力されたため 下記コマンドでインストールしました。
  - `types`というユーザーが公開している、型定義済みファイルのパッケージという意味のようです。
  - 参照：[npmでTypeScriptの型定義を管理できるtypesパッケージについて](https://qiita.com/lacolaco/items/ed1aadf335f12cd3618d)

```
npm install @types/zen-observable
```

- `@ts-ignore`や、`camelcase`関連のエラーが出力された場合は、`.eslintrc.js`に下記を追加してください。

```
  rules: {
     … ( 中略 ) …
    "@typescript-eslint/ban-ts-ignore": "off",   // 追記
    "@typescript-eslint/camelcase": "off",       // 追記
    "@typescript-eslint/no-explicit-any": "off", // 追記 
    "@typescript-eslint/no-empty-function": "off",  // 追記
  }
```

- それでも Amplify ビルド時に下記のようなエラーが出る場合は、`"skipLibCheck": true`を`tsconfig.json`に追記してください。( ライブラリチェックをスキップするようになるため、おすすめしません。)
  - 参照：[implicitly has an 'any' type (zen-observable, graphql/language/ast)](https://github.com/aws-amplify/amplify-js/issues/4754)

```
// Amplify ビルド時エラー
2020-03-29T10:50:07.776Z [INFO]: error  in /codebuild/output/src263382100/src/amplifytsproject/node_modules/@aws-amplify/api/lib-esm/types/index.d.ts
                                 ERROR in /codebuild/output/src263382100/src/amplifytsproject/node_modules/@aws-amplify/api/lib-esm/types/index.d.ts(1,30):
                                 1:30 Could not find a declaration file for module 'graphql/language/ast'. '/codebuild/output/src263382100/src/amplifytsproject/node_modules/graphql/language/ast.js' implicitly has an 'any' type.
                                 Try `npm install @types/graphql` if it exists or add a new declaration (.d.ts) file containing `declare module 'graphql/language/ast';`
                                 > 1 | import { DocumentNode } from 'graphql/language/ast';
                                 |                              ^
                                 2 | /**
                                 3 |  * RestClient instance options
                                 4 |  */
2020-03-29T10:50:07.776Z [WARNING]: ERROR  Build failed with errors.
```

```json(tsconfig.json)

{
  "compilerOptions": {
    "skipLibCheck": true,  // 追記
    "target": "esnext",
    "module": "esnext",
    … ( 以下略 ) …
```

- `src\store\index.ts`を下記のように修正してください。

```
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    user: null    // 追記
  },
  mutations: {
    setUser(state, user) {    // 追記
      state.user = user    // 追記
    }    // 追記
  },
  actions: {
  },
  modules: {
  }
})
```

- `src\router\index.ts`を下記のように修正してください。
  - 下記の記事を参考に設定しました。
  - 参照：[Try #024 – AWS AmplifyとVue.jsでログイン機能を構築してみた](https://day-journal.com/memo/try-024/#router-js)
  - tslint に３、４回ほど指摘を受けたため、追記部 ① ～ ③ を書く順番は大事です。

```
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
// ---------------↓↓追記部①ここから↓↓---------------
// @ts-ignore
import store from '../store'
// @ts-ignore
import { AmplifyEventBus, AmplifyPlugin, components } from 'aws-amplify-vue'

import * as AmplifyModules from 'aws-amplify'


Vue.use(AmplifyPlugin, AmplifyModules)
// ---------------↑↑追記部①ここまで↑↑---------------

Vue.use(VueRouter)

// ---------------↓↓追記部②ここから↓↓---------------
let user: any;

function getUser() {
  return Vue.prototype.$Amplify.Auth.currentAuthenticatedUser()
    .then((data: any) => {
      if (data && data.signInUserSession) {
        store.commit('setUser', data);
        return data;
      }
    }).catch(() => {
      store.commit('setUser', null);
      return null;
    });
}
// ---------------↑↑追記部②ここまで↑↑---------------

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home,
      meta: { requiresAuth: true }    // 追記
    },
    {                  // 追記
      path: '/auth',   // 追記  
      name: 'auth',    // 追記
      component: components.Authenticator  // 追記
    },                 // 追記
    {
      path: '/about',
      name: 'About',
      // route level code-splitting
      // this generates a separate chunk (about.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'),
      meta: { requiresAuth: true }    // 追記
    }
  ]
})

// ---------------↓↓追記部③ここから↓↓---------------
// ユーザー管理
getUser().then((user: any) => {
  if (user) {
    router.push({ path: '/' }, () => { }, () => { });
  }
});

// ログイン状態管理
AmplifyEventBus.$on('authState', async (state: any) => {
  if (state === 'signedOut') {
    user = null;
    store.commit('setUser', null);
    router.push({ path: '/auth' }, () => { }, () => { });
  } else if (state === 'signedIn') {
    user = await getUser();
    router.push({ path: '/' }, () => { }, () => { });
  }
});

router.beforeResolve(async (to, from, next) => {
  if (to.matched.some(record => record.meta.requiresAuth)) {
    user = await getUser();
    if (!user) {
      return next({
        path: "/auth",
        query: {
          redirect: to.fullPath
        }
      });
    }
    return next();
  }
  return next();
});
// ---------------↑↑追記部③ここまで↑↑---------------

export default router
```

- 最後に下記コマンドで、GitHub へ push してください。Amplify Console が更新されます。

```
git add .
git commit -m "完成！検証大変だった！( もっとちゃんとしたコメントを付けてください。)"
git push
```

### 結果
- `https://master.＜App ID＞.amplifyapp.com/`でアクセスすると、認証画面にリダイレクトされます。サインアップできることを確認してください。![signup.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518221/3f8d38cc-370c-d802-cc59-648c5d356c62.jpeg)
- サインインして Vue.js のサンプルページが表示されることを確認してください。![signin.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518221/df6850c9-5c25-02b8-8843-a457fd338eb6.jpeg)


## 2-7. ユーザーのサインアップの制限
- 今の設定のままでは、誰でもサインアップしてユーザー登録できてしまいます。
- 管理者のみユーザー登録ができるように設定を追加します。

### 前提
- 2-6. まで完了した状態にしてください。

### 操作
- Cognito サービス画面から下記のように操作し、最後に「変更の保存」を選択してください。![cognito-user-restriction.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518221/c428156f-7968-66f0-06de-d65da3fb3056.jpeg)

### 結果
- 新しいユーザーでサインアップしようとしても失敗することが確認できます。![signup-restriction.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518221/7b848fca-242e-40f8-d65c-0cb25b974cdc.jpeg)

## 2-8. ブランチ自動検出設定を追加
- 新規の Git ブランチを作成したときにバックエンドが自動で構築されるように設定します。

### 前提
- 2-6. まで完了した状態にしてください。( 2-7. は飛ばしても問題ありません。)
- Amplify 用サービスロールを作成しない場合、この節の操作は実施できませんのでご注意ください。
  - Amplify 用サービスロールを作成していない場合は、[2-4. の操作画面ショット](#2-4-vuejs-アプリをリリース)を参照して作成してください。
  - **Amplify 用サービスロールを作成する際に IAM Role に`AdministratorAccess`ポリシーの付与が必要です。**
  - サービスロールの信頼されたエンティティには Amplify のみ設定されます。 EC2 など他サービスにサービスロールが割り当てられることが無いため まだ安心かと思われます。( それでも世の IAM 担当者が聞いたら卒倒する気がしますが。。笑 )

### 操作
- Amplify サービス画面から ブランチ自動検出設定を有効化してください。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518221/86f5f8e9-f30f-0c89-9dad-cab8405d4151.png)

- `master`ブランチを基にして、`feature`ブランチを作成し、最後に GitHub に push してください。

```
$ git branch
* master

$ git checkout -b feature/fix-test
Switched to a new branch 'feature/fix-test'

$ git branch
* feature/fix-test
  master

$ git push origin feature/fix-test -u
```

### 結果
- Amplify サービス画面から新規フロントエンド / バックエンドが作成されていることが確認できます。![frontbackend.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518221/b8d64dc0-f88f-0dba-1170-c9128ff37d70.jpeg)

- feature ブランチにアクセスすると、下記のように Basic 認証と Cognito 認証の両方が追加されていることが確認できます。( この後サインアップとサインインすると Vue.js のページが表示されました。)![amplify+branch.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518221/aa37ec67-1b17-8c4f-8d58-32454dd6f7b0.jpeg)

- CloudFormation サービス画面からバックエンドの新規リソースが作成されていることが確認できます。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518221/791bdcc8-8813-2b36-2596-60e5970205b1.png)

### オプション操作
- 下記のようにコマンドを実行してローカルに Amplify の環境設定を反映させてください。

```
$ amplify env list  // まだ featurefix 環境はローカルに反映されていません。

| Environments |
| ------------ |
| *prod        |

$ amplify pull --appId <App ID> --envName featurefix  // 2-8. の結果の時にコピーしたコマンドを実行します。

For more information on AWS Profiles, see:
https://docs.aws.amazon.com/cli/latest/userguide/cli-multiple-profiles.html

? Do you want to use an AWS profile? Yes
? Please choose the profile you want to use tsproject
Amplify AppID found: <App ID>. Amplify App name is: tsproject
Backend environment featurefix found in Amplify Console app: tsproject
? Choose your default editor: Visual Studio Code
? Choose the type of app that you're building javascript
Please tell us about your project
? What javascript framework are you using vue
? Source Directory Path:  src
? Distribution Directory Path: dist
? Build Command:  npm.cmd run-script build
? Start Command: npm.cmd run-script serve

? Do you plan on modifying this backend? Yes

Successfully pulled backend environment featurefix from the cloud.
Run 'amplify pull' to sync upstream changes.


$ amplify env list  // featurefix 環境がローカルに反映されました。

| Environments |
| ------------ |
| *featurefix  |   // 追加されています。
| prod         |


$ amplify pull

Pre-pull status:

Current Environment: featurefix

| Category | Resource name     | Operation | Provider plugin   |
| -------- | ----------------- | --------- | ----------------- |
| Hosting  | amplifyhosting    | No Change |                   |
| Auth     | tsproject1cc0f2f5 | No Change | awscloudformation |

√ Successfully pulled backend environment featurefix from the cloud.
… ( 以下略 ) …
```
- **この操作により、Amplify CLI を使って featurefix 環境に対して設定変更 ( API やデータストアの追加など ) をしていくことができるようになります。**

操作 & 結果は以上です。

# まとめ
- Amplify ( Console + CLI + Framework ) + Vue.js で認証機能付きの Web サイトを作成することができました。
  - Amplify に用意されている認証用ページをそのまま使うことができるため、よりコンテンツの中身に集中できるようになっています。
  - `amplify api add`等、他のカテゴリの機能を追加する足掛かりができました。

# 最後に
- TypeScript で作られた Vue.js プロジェクトに Amplify Framework を組み込むのはあまり事例が無いようで、とりあえず「落とし穴がたくさんある」ことは分かって良かったです。
- AppSync 、DynamoDB の通信状況を X-Ray でグラフィカルに表示できるようになったようなので 次は`amplify api add`の検証をしてみたいと考えています。
  - 参照：[Improving GraphQL Observability with AWS AppSync Tracing Support (AWS Mobile Blog) ](https://aws.amazon.com/jp/blogs/mobile/graphql-observability-appsync-xray/)
- この記事内でお気づきになった点や修正が必要な記載がありましたら、ご指摘いただけますと幸いです。
- 最後になりましたが参照記事を執筆された方々に感謝を申し上げます。ありがとうございました。