6
6

Amazon Cognitoとvue.jsでユーザーログインできるウェブアプリを作る

Last updated at Posted at 2024-08-03

この記事ではAmazon Cognitoによるユーザー管理の機能を搭載するウェブサイトの作成サンプルを説明します。フロントエンドはvue.jsTypeScript)フレームワークでバックエンドは無しです。

はじめに

Amazon CognitoはAWSのサービスの一つです。詳しくは既に色んな説明の記事があるので割愛しますが、簡単にいうとユーザーの登録やログインや情報管理をする機能を実現するための便利な方法です。

基本的にAWSに登録したらAmazon Cognitoをすぐ作成して無料で使うことができます。

普段ログインシステムを作るならバックエンドでSQLなどのデータベースが必要とするはずですが、Amazon Cognitoはその部分を準備してくれるので、バックエンドなしでフロントエンドだけでウェブアプリを作ることができて便利です。

この記事ではAmazon Cognitoの使い方を勉強するために簡単なウェブアプリを作る例を挙げます。

フレームワークなしでただのJavaScriptでもAmazon Cognitoを実装することができますが、フレームワークを使った方がやはり楽です。私はいつもvue.jsを使っているので、今回の例もフロントエンドをvue.jsで書きます。

TypeScriptで書きますが、普通にJavaScriptで書く場合も似ているので、Amazon Cognitoを使った三井人のための参考になったら幸いです。

目標のアプリ

どんなウェブアプリが作れるかとりあえず見ておきましょう。

まずはアクセスしたらこんな画面になります。

caq01.png

ここでログインしなければ何もできません。初めてアクセスしてまだユーザー登録氏ていない人は右下のボタンを押します。

そうしたらユーザー登録画面に切り替えます。

caq02.png

因みに左上の「Ξ」をクリックしたら左の方にユーザー登録画面とログイン画面のリンクが現れます。もう一度クリックしたら消えます。

caq03.png

試しにユーザー登録の情報を入れて送信したら認識コードが入力したメールへ送られます。同時にこの認証の画面に切り替えます。

caq04.png

認証コードを入力して送信したらユーザー登録は完了です。自動的にログイン画面に戻ります。

caq05.png

そしてログインしたらこのような画面になります。ユーザー名と姓名も上に表示されます。

caq06.png

この画面は本来は使いたいアプリの画面ですが、今回はただログインシステムのサンプルをしたいので、アプリの中身を作らずにここで終わります。

因みに「杏」を書いたのは、杏は英語でアプリコット(apricot)だからです。「アプリ」とcognitoだから「apricot」。ただ適当です。

その他に左の「Ξ」をクリックしたら左の選択も変わって、情報更新とパスワード変更の画面に入ることもできます。

caq07.png
caq08.png

尚、一度ログインしたら道道的にログイン状態がセッションストレージに保存されて、今後もう一度アクセスしたらそのままログインの状態です。

ログアウトしたらセッションストレージがクリアされてログイン状態が終わります。

最後にもしパスワードを忘れたらログインの画面に戻って左下のボタンを押すと認証コードが送られてパスワード再設定の画面に入ります。

caq09.png

以上、簡単なアプリのテストと説明です。

Cognitoユーザープールの作成

次はAmazon Cognitoを始める方法について説明します。

まずはAWSアカウントの登録をする必要があります。AWSの登録や使い方に関してはとりあえず割愛して、既に登録していてある程度使っているという前提で話を進めます。

検索の欄で「cog」などで検索してみたらCognitoが見つかります。

caqa01.png

Cognitoの最初の画面に入ったら「ユーザープールを作成」をクリックします。

caqa02.png

ユーザープールというのは、簡単にいうとユーザーの情報を登録するデータベースです。ユーザーのデータはAWSのサーバーに保存されて、これに接続することでデータ追加や取得や更新や削除ができます。

だからCognitoの使用はまずユーザープールの作成から始めます。

作成画面です。

caqa03.png

選択の項目が多くて今すぐ理解する必要がないと思うので、私が調整した部分だけ姓名します。その他は特にわからなければ既定値のままでいいです。

まずサインインオプションはユーザー名だけか電子メールや電話番号でログインすることもできますが、ここではユーザー名だけにしておきます。そしてユーザー名は制限なしどんな名前も使えるようにします。大文字と小文字の区別もちゃんとします。

caqa04.png

次はパスワードの制限です。既定値のままだと制限が多くてややこしいので、全部の制限を外してどんなパスワードも使えるようにします。最小文字数は既定値の8のままでいいです。

caqa05.png

多要素認証はなしにします。

caqa06.png

ユーザーアカウントの復旧は電子メールでできるように設定します。

caqa07.png

次は登録したいユーザーの属性です。以前の選択によって電子メールは既に必須になっていますが、その他にも色々追加できます。今回は「name」つまりフルネームだけ追加します。

caqa08.png

次は認証メールを送る電子メールアドレスの設定です。左がお勧めとされているようですが、今回は簡単なサンプルのため右のCognitoでいいです。

caqa09.png

次はユーザープールの名前です。これはあまり重要ではないので適当でいいと思います。

caqa10.png

それとアプリケーションクライアントの名前、これも適当でいいです。

caqa11.png

最後にクライアントシークレット、これも今回は生成しなくていいです。

caqa12.png

全部の選択が終わったら確認画面に入って、「ユーザープールを作成」ボタンを押したら完成です。

caqa13.png

そしてユーザープールが表示される画面に入ります。今作成したユーザープールはここにあります。ここで重要なのは「ユーザープールID」です(適当に名付けしたユーザープール名ではない)。後で使うのでここではとりあえずコピーして起きましょう。

caqa14.png

作成されたユーザープールの名前をクリックして詳細を調べてみます。ここで「アプリケーションの統合」の項目を探してクリックします。

caqa15.png

そうしたら先程入力したアプリケーションクライアント名が表示されます。そしてクライアントIDもここに書いてあるのでこれも必要なものなのでコピーして起きます。

caqa16.png

AWS側の準備はこれで整いました。

尚、ユーザー登録をしたらすぐここのユーザーのリストに反映されます。

caqa17.png

実装

環境設定

次は作成しておいたユーザープールに接続してユーザー管理をするための実装です。ここではまず今回の実行で使ったパソコンの環境設定について説明しておきます。

使うライブラリーとバージョン。

vue 3.4.31
vuetify 3.6.11
vuex 4.1.0
amazon-cognito-identity-js 6.3.12
vite 5.3.3
yarn 1.22.22
typescript 5.4.2

amazon-cognito-identity-jsはAmazon Cognitoに接続するためのライブラリーです。ウェブアプリを構成するコンポネントはvuetifyを使います。今回は沢山コンポネントに分けられてCognitoからのユーザーデータが各コンポーネントに渡されるのでそのデータを簡単に扱うためにvuexを使います。

先月もvuetifyを使ったサンプルを作って記事を書いたのですが、あの時と比べたらバージョンが少し上がって、変化も少し見えます。

プロジェクト作成

ここでプロジェクトの作成はyarnで行いますが、npmやbunでもできます。

yarn create vuetify
yarn create v1.22.22
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 🔨  Building fresh packages...
success Installed "create-vuetify@2.2.6" with binaries:
      - create-vuetify
[##########] 10/10
Vuetify.js - Material Component Framework for Vue

✔ Project name: … cogvueto
✔ Which preset would you like to install? › Barebones (Only Vue & Vuetify)
✔ Use TypeScript? … No / Yes
✔ Would you like to install dependencies with yarn, npm, pnpm, or bun? › yarn
✔ Install Dependencies? … No / Yes

◌ Generating scaffold...
◌ Installing dependencies with yarn...

yarn install v1.22.22
info No lockfile found.
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 🔨  Building fresh packages...
success Saved lockfile.
✨  Done in 15.56s.

cogvueto has been generated at /Users/phyblas/Library/CloudStorage/Dropbox/web/cogvueto/cogvueto

Discord community: https://community.vuetifyjs.com
Github: https://github.com/vuetifyjs/vuetify
Support Vuetify: https://github.com/sponsors/johnleider
✨  Done in 83.02s.

プロジェクトの名前は、cognitoとvueだから「cogvueto」にします。

作成する時に出てきた選択肢はここに書いておきます。

✔ Barebones (Only Vue & Vuetify)
✔ Yes
✔ yarn
✔ Yes

プロジェクトフォルダに入ります。

cd cogvueto

vuetifyの他にvuexとamazon-cognito-identity-jsが必要なので追加します。

yarn add vuex
yarn add v1.22.22
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 🔨  Building fresh packages...
success Saved lockfile.
success Saved 2 new dependencies.
info Direct dependencies
└─ vuex@4.1.0
info All dependencies
├─ @vue/devtools-api@6.6.3
└─ vuex@4.1.0
✨  Done in 1.22s.
yarn add amazon-cognito-identity-js
yarn add v1.22.22
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 🔨  Building fresh packages...
success Saved lockfile.
success Saved 18 new dependencies.
info Direct dependencies
└─ amazon-cognito-identity-js@6.3.12
info All dependencies
├─ @aws-crypto/sha256-js@1.2.2
├─ @aws-crypto/util@1.2.2
├─ @aws-sdk/util-utf8-browser@3.259.0
├─ @smithy/types@3.3.0
├─ amazon-cognito-identity-js@6.3.12
├─ base64-js@1.5.1
├─ buffer@4.9.2
├─ fast-base64-decode@1.0.0
├─ ieee754@1.2.1
├─ isarray@1.0.0
├─ isomorphic-unfetch@3.1.0
├─ js-cookie@2.2.1
├─ node-fetch@2.7.0
├─ tr46@0.0.3
├─ tslib@2.6.3
├─ unfetch@4.2.0
├─ webidl-conversions@3.0.1
└─ whatwg-url@5.0.0
✨  Done in 2.05s.

これで基本的なプロジェクトの準備は完了です。次は自分でコードを書く段階に入ります。

実装のコード

完成した後のプロジェクトフォルダはこんな感じになります。

caq18.png

ここで青になっている部分は自分で作成したファイルと編集した部分が含まれるファイルです。その以外はそのままで何かする必要がありません。

App.vueは最初からあるファイルですが、殆ど最初から書き直しです。componentsフォルダの中の.vueは全部自分で作ったコンポネントです。コンポネントは全部10ですが、それぞれそこまで大きくはありません。ただわかりやすいようにできるだけ細かく分けるだけ。

index.html

まずはindex.htmlです。これは元からあった重要なファイルですが、特に変更する必要なくそのまま使ってもいい場合も多いですが、今回重要なのは window.global = window;を入れるというところです。これがないとエラーになります。これについてこの記事に説明があります。

index.html
<!DOCTYPE html>
<html lang="ja">

<head>
  <meta charset="UTF-8" />
  <link rel="icon" href="/favicon.ico" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>≈cogvueto≈</title>
</head>

<body>
  <div id="app"></div>
  <script type="module" src="/src/main.ts"></script>
</body>

</html>

<script>
  window.global = window;
</script>

src/main.ts

ここにcogintoのクラスを定義してインスタンスを作成して、各コンポネントから使えるようにvuexのstoreに渡します。

CognitoUserPoolを作成する部分のUserPoolIdClientIdは予めユーザープールを作成した時に準備しておいたユーザープールIDとクライアントIDを入れます。(以下のコードの中に書いてあるのは本物ではなくそれっぽい適当なIDです)

Storage: sessionStorageの指定は、ログイン状態のデータをセッションストレージに保存するためです。指定しないままのデフォルトではローカルストレージに保存されるということになりますが、セッションストレージの方がいいです。

src/main.ts
import { registerPlugins } from '@/plugins';
import App from './App.vue';
import { createApp } from 'vue';

const app = createApp(App);
registerPlugins(app);

import { createStore } from "vuex";
import { CognitoUser, CognitoUserPool } from "amazon-cognito-identity-js";

class Cognito {
  user_pool: CognitoUserPool;
  user: CognitoUser | null;
  username: string = "";
  fullname: string = "";
  email: string = "";
  sousa: string = "";
  login_shita: boolean = false;

  constructor() {
    this.user_pool = new CognitoUserPool({
      UserPoolId: "ap-northeast-3_kNoREwYnI",
      ClientId: "oq5h2pl3i9600jni2a0j155g77",
      Storage: sessionStorage
    });
    this.user = this.user_pool.getCurrentUser();
  }

  set_user() {
    this.user = new CognitoUser({
      Username: this.username,
      Pool: this.user_pool,
      Storage: sessionStorage,
    });
  }

  get_attr() {
    this.user!.getUserAttributes((err, res) => {
      if (!err && res) {
        res.forEach((attr) => {
          if (attr.Name == "name") { this.fullname = attr.Value; }
          else if (attr.Name == "email") { this.email = attr.Value; }
        });
      }
      else { alert(err); }
    });
  }
}

const store = createStore({
  state: {
    cognito: new Cognito()
  }
});
app.use(store);
app.mount('#app');

src/vuex.d.tsとsrc/store.d.ts

これはTypeScriptの型のエラーを解消するために追加されるものです。

src/vuex.d.ts
declare module "vuex" {
  export * from "vuex/types/index.d.ts";
  export * from "vuex/types/helpers.d.ts";
  export * from "vuex/types/logger.d.ts";
  export * from "vuex/types/vue.d.ts";
}
src/store.d.ts
import { ComponentCustomProperties } from "vue";
import { Store } from "vuex";

declare module "@vue/runtime-core" {
  interface ComponentCustomProperties {
    $store: Store
  }
}

src/App.vue

ウェブアプリの一番外の構造を成す部分です。ここから各コンポネントが呼び出されて構成されます。基本的に3つの部分に分けられます。

  • ueno.vue:上のログイン状態を表示するv-app-bar
  • nishino.vue:左のリストのv-navigation-drawer
  • nakano.vue:メイン画面を構成するv-main

因みに上の方にあるからuenoで、左にあるからnishino……など名前は適当です。

src/App.vue
<template>
  <v-app>
    <ueno @drawer="drawer = !drawer" />
    <nishino v-if="drawer" />
    <nakano />
  </v-app>
</template>

<script lang="ts">
export default {
  data() {
    return {
      drawer: false
    };
  }
}
</script>

src/components/ueno.vue

v-app-barタグによって作れた上の部分です。ログインした状態ではユーザー名を表示します。

src/components/ueno.vue
<template>
  <v-app-bar class="py-0 my-0" color="green" short app>
    <v-app-bar-nav-icon @click.stop="$emit('drawer')" />
    <v-toolbar-title v-if="cognito.login_shita">
      {{ cognito.username }}{{ cognito.fullname }})ですが、何か?
    </v-toolbar-title>
    <v-toolbar-title v-else>名乗るほどの者ではない</v-toolbar-title>
  </v-app-bar>
</template>

<script lang="ts">
export default {
  computed: {
    cognito() {
      return this.$store.state.cognito;
    }
  },
};
</script>

src/components/nishino.vue

v-navigation-drawerタグから作られたメニュー。ログインした状態とログインしていない状態とは表示が違います。ここのメニューをクリックすることで画面が切り替えられます。

src/components/nishino.vue
<template>
  <v-navigation-drawer color="purple" width="150" mini-variant-width permanent>
    <v-list>
      <v-list-item v-if="!cognito.login_shita" @click="cognito.sousa = '登録'" title="新規登録" />
      <v-list-item v-if="!cognito.login_shita" @click="cognito.sousa = 'ログイン'" title="ログイン" />
      <v-list-item v-if="cognito.login_shita" @click="cognito.sousa = '情報更新'" title="情報更新" />
      <v-list-item v-if="cognito.login_shita" @click="cognito.sousa = 'パスワード変更'" title="パスワード変更" />
      <v-list-item v-if="cognito.login_shita" @click="logout_suru" title="ログアウト" />
    </v-list>
  </v-navigation-drawer>
</template>

<script lang="ts">
export default {
  computed: {
    cognito() {
      return this.$store.state.cognito;
    }
  },
  methods: {
    logout_suru() {
      this.cognito.login_shita = false;
      this.cognito.sousa = "ログイン";
      this.cognito.user.signOut();
    },
  },
};
</script>

src/components/nakano.vue

この部分はメイン画面で、以下の7つのコンポネントが条件によって使われます。又、最初にアクセスした時にセッションストレージをチェックすることによってログインしているかどうかを確認する処理のコードもこのコンポネントのmountedに書いてあります。ログイン状態になっていない場合はログイン画面に入りますが、ログインしている場合はアプリのメイン画面(ここでは大きな「杏」の字のある画面)に入ります。

src/components/nakano.vue
<template>
  <v-main>
    <login v-if="cognito.sousa == 'ログイン'" />
    <touroku v-else-if="cognito.sousa == '登録'" />
    <ninshou v-else-if="cognito.sousa == '認証'" />
    <jouhou-koushin v-else-if="cognito.sousa == '情報更新'" />
    <password-henkou v-else-if="cognito.sousa == 'パスワード変更'" />
    <password-saisettei v-else-if="cognito.sousa == 'パスワード再設定'" />
    <anzu v-else-if="!cognito.sousa && cognito.login_shita" />
  </v-main>
</template>

<script lang="ts">
export default {
  computed: {
    cognito() {
      return this.$store.state.cognito;
    }
  },
  mounted() {
    let cognito = this.cognito;
    if (cognito.user) {
      cognito.user.getSession((err: Error) => {
        if (!err) {
          cognito.login_shita = true;
          cognito.username = cognito.user.username;
          cognito.get_attr();
        }
        else { alert(err); }
      });
    }
    else {
      cognito.sousa = "ログイン";
    }
  },
};
</script>

src/components/login.vue

ログインの画面。

src/components/login.vue
<template>
  <v-container class="px-1 py-1" style="max-width: 500px;">
    <div class="px-5 py-2 text-h5">まずはログインしてね</div>
    <div style="text-align: center;">
      <v-text-field class="mx-3 my-1" v-model="cognito.username" label="ユーザーだよ" hide-details />
      <v-text-field class="mx-3 my-1" v-model="cognito.password" label="パスワードだよ" type="password" hide-details />
      <v-btn class="mx-1 my-3 text-h6" @click="login_suru" color="primary" style="width: 300px;">
        では、ログインするよ
      </v-btn>
    </div>
    <div class="d-flex justify-center">
      <v-btn class="mx-1 my-1" @click="password_saisettei_suru" color="warning">パスワード忘れちゃった</v-btn>
      <v-btn class="mx-1 my-1" @click="cognito.sousa = '登録'" color="secondary">まだ登録してないんだが</v-btn>
    </div>
  </v-container>
</template>

<script lang="ts">
import { AuthenticationDetails } from "amazon-cognito-identity-js";

export default {
  computed: {
    cognito() {
      return this.$store.state.cognito;
    }
  },
  methods: {
    login_suru() {
      let cognito = this.cognito;
      if (cognito.username == "" || cognito.password == "") {
        alert("ユーザー名とパスワードを入力してから押してね");
        return;
      }
      cognito.set_user();
      cognito.user.authenticateUser(
        new AuthenticationDetails({
          Username: cognito.username,
          Password: cognito.password
        }),
        {
          onSuccess() {
            cognito.sousa = "";
            cognito.login_shita = true;
            cognito.get_attr();
          },
          onFailure(err: Error) { alert(err); },
        }
      );
    },
    password_saisettei_suru() {
      let cognito = this.cognito;
      if (cognito.username == "") {
        alert("ユーザー名を入力して");
        return;
      }
      cognito.set_user();
      cognito.user.forgotPassword({
        onSuccess: () => {
          cognito.sousa = "パスワード再設定";
        },
        onFailure: (err: Error) => { alert(err); }
      });
    }
  },
};
</script>

src/components/touroku.vue

新規ユーザー登録の画面。

src/components/touroku.vue
<template>
  <v-container class="px-1 py-1" style="max-width: 500px; ">
    <div class="px-5 py-2 text-h5">ユーザーがなければ作ればいい</div>
    <div style="text-align: center;">
      <v-text-field class="mx-3 my-1" v-model="cognito.username" label="ユーザーだが" hide-details />
      <v-text-field class="mx-3 my-1" v-model="cognito.password" type="password" label="パスワードだが" hide-details />
      <v-text-field class="mx-3 my-1" v-model="cognito.email" label="電子メールだが" hide-details />
      <v-text-field class="mx-3 my-1" v-model="cognito.fullname" label="姓名だが" hide-details />
      <v-btn class="mx-1 my-3 text-h6" @click="touroku_suru" color="primary" style="width: 300;">
        では、登録するぜ
      </v-btn>
    </div>
  </v-container>
</template>

<script lang="ts">
import { CognitoUserAttribute } from "amazon-cognito-identity-js";

export default {
  computed: {
    cognito() {
      return this.$store.state.cognito;
    }
  },
  methods: {
    touroku_suru() {
      let cognito = this.cognito;
      if (
        cognito.username == "" ||
        cognito.password == "" ||
        cognito.email == "" ||
        cognito.fullname == ""
      ) {
        alert("まだ入力していない項目があるんだけど");
        return;
      }
      const re = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
      if (!re.test(cognito.email)) {
        alert("電子メールはこんなもんではないはずだけど");
        return;
      }
      const lis_attr = [
        new CognitoUserAttribute({ Name: "email", Value: cognito.email }),
        new CognitoUserAttribute({ Name: "name", Value: cognito.fullname })
      ];
      cognito.user_pool.signUp(
        cognito.username,
        cognito.password,
        lis_attr,
        null,
        (err: Error) => {
          if (!err) {
            cognito.sousa = "認証";
          }
          else { alert(err); }
        }
      );
    },
  },
};
</script>

src/components/ninshou.vue

ユーザー登録の認証を行う画面。

src/components/ninshou.vue
<template>
  <v-container class="px-1 py-1" style="max-width: 500px;">
    <div class="px-5 py-2 text-h5">認証しよう</div>
    <div style="text-align: left;">
      <div class="mx-3 my-1">指定したメールに認証コードを送ったよ。</div>
      <div class="mx-3 my-1">ユーザー登録を完成させるために入力してね。</div>
    </div>
    <v-card class="align-center justify-center" style="text-align: center;">
      <div class="px-2 py-1">ユーザ:<span class="text-h6">{{ cognito.username }}</span></div>
      <v-text-field class="mx-3 my-1" v-model="ninshou_code" label="送られた認証コード" hide-details />
      <v-btn class="mx-1 my-2 text-h6" @click="ninshou_suru" color="primary" style="width: 220px;">
        認証しちゃう
      </v-btn>
    </v-card>
  </v-container>
</template>

<script lang="ts">
export default {
  data() {
    return {
      ninshou_code: ""
    };
  },
  computed: {
    cognito() {
      return this.$store.state.cognito;
    }
  },
  methods: {
    ninshou_suru() {
      let cognito = this.cognito;
      cognito.set_user();
      cognito.user.confirmRegistration(
        this.ninshou_code,
        true,
        (err: Error) => {
          if (!err) {
            cognito.sousa = "ログイン";
            alert("ユーザー登録完了");
          }
          else { alert(err); }
        }
      );
    },
  },
};
</script>

src/components/jouhou-koushin.vue

情報更新をする画面。

src/components/jouhou-koushin.vue
<template>
  <v-container class="px-1 py-1" style="max-width: 500px;">
    <div class="text-h5 px-5 py-2">ユーザー情報を変更していいの?</div>
    <div style="text-align: center;">
      <v-text-field class="mx-3 my-1" v-model="email" label="電子メール" hide-details />
      <v-text-field class="mx-3 my-1" v-model="fullname" label="姓名" hide-details />
      <v-btn class="mx-3 my-1 text-h6" @click="koushin_suru" color="primary" style="width: 300px;">
        情報更新しちゃうよ
      </v-btn>
      <v-btn class="mx-3 my-1 text-h6" @click="cognito.sousa = ''" color="warning" style="width: 300px;">
        やはりこのままでいいや
      </v-btn>
    </div>
  </v-container>
</template>

<script lang="ts">
import { CognitoUserAttribute } from "amazon-cognito-identity-js";

export default {
  data() {
    return {
      email: "",
      fullname: ""
    };
  },
  computed: {
    cognito() {
      return this.$store.state.cognito;
    }
  },
  methods: {
    koushin_suru() {
      let cognito = this.cognito;
      cognito.user.getSession((err: Error) => {
        if (!err) {
          cognito.user.updateAttributes(
            [
              new CognitoUserAttribute({ Name: "email", Value: this.email }),
              new CognitoUserAttribute({ Name: "name", Value: this.fullname })
            ],
            (err: Error) => {
              if (!err) {
                cognito.sousa = "";
                cognito.get_attr();
                alert("情報更新完了");
              }
              else { alert(err); }
            }
          );
        }
        else { alert(err); }
      });
    },
  },
  mounted() {
    this.email = this.cognito.email;
    this.fullname = this.cognito.fullname;
  }
};
</script>

src/components/password-henkou.vue

パスワード変更をする画面。

src/components/password-henkou.vue
<template>
  <v-container class="px-1 py-1" style="max-width: 500px;">
    <div class="text-h5 px-5 py-2">パスワードを変更したいの?</div>
    <div style="text-align: center;">
      <v-text-field class="mx-3 my-1" v-model="imano_password" type="password" label="今のパスワード" hide-details />
      <v-text-field class="mx-3 my-1" v-model="aratana_password" type="password" label="新たなパスワード" hide-details />
      <v-btn class="mx-3 my-1 text-h6" @click="henkou_suru" color="primary" style="width: 300px;">
        パスワード変更しちゃうよ
      </v-btn>
      <v-btn class="mx-3 my-1 text-h6" @click="cognito.sousa = ''" color="warning" style="width: 300px;">
        やはりこのままでいいや
      </v-btn>
    </div>
  </v-container>
</template>

<script lang="ts">
export default {
  data() {
    return {
      imano_password: "",
      aratana_password: ""
    };
  },
  computed: {
    cognito() {
      return this.$store.state.cognito;
    }
  },
  methods: {
    henkou_suru() {
      let cognito = this.cognito;
      cognito.user.getSession((err: Error) => {
        if (!err) {
          cognito.user.changePassword(
            this.imano_password,
            this.aratana_password,
            (err: Error) => {
              if (!err) {
                cognito.sousa = "";
                alert("パスワード変更完了");
              }
              else { alert(err); }
            }
          );
        }
        else { alert(err); }
      });
    },
  }
};
</script>

src/components/password-saisettei.vue

パスワードを忘れた場合、メールで送られた認証コードを入力して再設定を行うための画面。

src/components/password-saisettei.vue
<template>
  <v-container class="px-1 py-1" style="max-width: 500px;">
    <div class="text-h5 px-5 py-2">うっかりパスワードを忘れたあなたのため</div>
    <div style="text-align: center;">
      <v-text-field class="mx-3 my-1" v-model="ninshou_code" label="認証コード" hide-details />
      <v-text-field class="mx-3 my-1" v-model="cognito.password" type="password" label="新しいパスワード" hide-details />
      <v-btn class="mx-3 my-1" @click="saisettei_suru" color="primary" style="width: 300px;">
        パスワード再設定しちゃうよ
      </v-btn>
    </div>
  </v-container>
</template>

<script lang="ts">
export default {
  data() {
    return {
      ninshou_code: ""
    };
  },
  computed: {
    cognito() {
      return this.$store.state.cognito;
    }
  },
  methods: {
    saisettei_suru() {
      let cognito = this.cognito;
      cognito.user.confirmPassword(this.ninshou_code, cognito.password, {
        onSuccess: () => {
          cognito.sousa = "ログイン";
          alert("パスワード再設定完了");
        },
        onFailure: (err: Error) => { alert(err); }
      });
    }
  }
};
</script>

src/components/anzu.vue

アプリを使用するメイン画面。本来この画面に入ってアプリを使用するためにログインするので、本番ではこの部分こそメインとなるはずですが、今は「杏」の字以外何も入れられていません。

src/components/anzu.vue
<template>
  <v-container class="px-1 py-1" style="width: 500px; text-align: center; font-size: 300px; 
    background-color: brown; color:lightsalmon;"></v-container>
</template>

以上、全部のコンポネントが揃いました。それぞれ役割があって一つのアプリを構成します。

ログイン機能を入れるために色々な操作が関わって複雑になりますが、このようにわかりやすくコンポネントを分けられるのもvue.jsの便利なところです。

参考

基本とユーザープールの作成

JavaScriptによる実装

vue.jsによる実装

TypeScript

セッションストレージとトークンに関して

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6