AWS Amplify を使って WEB アプリを実装してみた（認証編）

# はじめに

[AWS Amplify を使って WEB アプリを実装してみた（プロジェクト作成編）](https://qiita.com/morio1101/items/9b8187e6a67b7e84a112) にて Vue プロジェクトの作成とバックエンド (Cognito) の作成を行ったので、実際に作成したプロジェクトを使用してデフォルトの認証機能を利用してみたいと思います

# 開発環境

* Windows 10
* nodist(nodeのバージョン管理)
    * node 12.13.0
* VSCode

# 今回のゴール

* 認証機能を作成する
    * ログインフォームについてはライブラリ依存ものを使用する

# 作業タスク

## Vue プロジェクトを修正する

``` javascript:main.js
 import Vue from "vue";
 import App from "./App.vue";
 import router from "./router";
+import Amplify from "aws-amplify";
+import aws_exports from "./aws-exports";
+
+Amplify.configure(aws_exports);

Vue.config.productionTip = false;

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

前回の工程で、バックエンドの作成が完了するとディレクトリ内の src ディレクトリに `aws-exports.js` が作られているので、このファイルを vue プロジェクトの src ディレクトリに配置する

そのあと接続に必要な import 文を追加したあとに、 `Amplify.configure` に設定内容を引数として渡す

``` javascript:router/index.js
@@ -1,14 +1,55 @@
 import Vue from "vue";
 import VueRouter from "vue-router";
+import { components, AmplifyEventBus, AmplifyPlugin } from "aws-amplify-vue";
+import * as AmplifyModules from "aws-amplify";
+
 import Home from "../views/Home.vue";

 Vue.use(VueRouter);
+Vue.use(AmplifyPlugin, AmplifyModules);
+
+let user;
+
+getUser().then((user, error) => {
+  if (user) {
+    router.push({ path: "/" });
+  }
+});
+
+AmplifyEventBus.$on("authState", async state => {
+  if (state === "signedOut") {
+    user = null;
+    router.push({ path: "/auth" });
+  } else if (state === "signedIn") {
+    user = await getUser();
+    router.push({ path: "/" });
+  }
+});
+
+function getUser() {
+  return Vue.prototype.$Amplify.Auth.currentAuthenticatedUser()
+    .then(data => {
+      if (data && data.signInUserSession) {
+        return data;
+      }
+    })
+    .catch(e => {
+      return null;
+    });
+}

 const routes = [
   {
     path: "/",
     name: "home",
-    component: Home
+    component: Home,
+    meta: { requiresAuth: true }
+  },
+  {
+    path: "/auth",
+    name: "Authenticator",
+    component: components.Authenticator
   },
   {
     path: "/about",
@@ -27,4 +68,20 @@ const router = new VueRouter({
   routes
 });

+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;
```
beforeResolve はすべてのコンポーネント内ガードと非同期ルートコンポーネントが解決された後、ナビゲーションが解決される直前に呼び出されるようで、今回の処理では routes 内で `meta: { requiresAuth: true }` を書いているルートのアクセスをしたとき認証を行っています
各コンポーネントの発生するイベントは AmplifyEventBus 経由で受け取れるので、ここではステータスの判断をしている感じなんですね

上記の変更をしてサーバーを立ち上げると以下のようなフォームが表示されて認証が出来る状態になっています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532289/ef0b20d5-5e9e-88bc-4130-2f966a125976.png)
これだけのソースを書き込むだけで、以下の機能が実装できることに驚きです:hushed:

* ユーザ認証
* ユーザ登録
* パスワードリセット

今回は試しにデフォルトの状態で認証機能を作ってみましたが、一から Cognito で実装するより断然楽でした！
今はデフォルトのままなので、英語の画面になっていますが・・・
Amplify を用いた状態で日本語翻訳する方法みたいなブログもあったので、次はページをカスタマイズする方法を調べて挑戦していきたいと思います！

今回までの修正内容は以下にアップしています
https://github.com/rararamorio/aws-amplify-example


# 参考サイト

* [VueにAmplifyを入れてみた](https://keinumata.hatenablog.com/entry/2018/12/04/001448)
* [ナビゲーションガード](https://router.vuejs.org/ja/guide/advanced/navigation-guards.html#%E3%82%B0%E3%83%AD%E3%83%BC%E3%83%90%E3%83%AB%E3%83%93%E3%83%95%E3%82%A9%E3%83%BC%E3%82%AC%E3%83%BC%E3%83%89)