見出し画像

【ワンピースで覚えるNuxt】ミドルウェア/ログイン機能


認証情報の保存

useCookie

クッキーオブジェクトはリアクティブな変数

interfaces.ts

export interface Character {
  id: number;
  name: string;
  bounty: number;
}

export interface ReturnJSONCharacters {
  result: number;
  data: Character[];
}

export interface User {
  id: number;
  name: string;
  loginId: string;
  password: string;
}
//ログインユーザサーバAPIエンドポイント
//レスポンスオブジェクト
export interface ReturnJSONAuth {
  result: number;
  token: string;//認証が通らなかった場合空文字
  user: User | null;//認証が通らなかった場合null
}

server/routes/user-management/auth.post.ts

import type { User, ReturnJSONAuth } from "@/interfaces";

export default defineEventHandler(
  async (event): Promise<ReturnJSONAuth> => {
    //レスポンスオブジェクトの各プロパティの初期値を用意。
    let resultVal = 0;
    let tokenVal = "";
    let loginUser: User|null = null;

    try{
      // throw createError("擬似エラー発生。");
      //リクエストボディを取得。
      const body = await readBody(event);
      //この時点でエンドポイント側の処理は成功とみなす。
      resultVal = 1;
      //ログインIDとパスワードが正しければ…
      if(body.loginId == "onepiece" && body.password == "bounty") {
        //アクセストークンを生成。
        tokenVal = "abcabcabcabcab";
        //ログインユーザ情報を格納。
        loginUser = {
          id: 1,
          name: "尾田栄一郎",
          loginId: body.loginId,
          password: ""
        }
      }
    }
    //エラー処理。
    catch(err) {
      console.log(err);
    }
    //レスポンスオブジェクトをリターン。
    return {
      result: resultVal,
      token: tokenVal,
      user: loginUser
    };
  }
);

pages/login.vue

<script setup lang="ts">
import type {User} from "@/interfaces";

//ログイン入力コントール用テンプレート変数。
const loginId = ref("");
//パスワード入力コントール用テンプレート変数。
const password = ref("");
//ペンディング(読込中)かどうかを表すテンプレート変数。
const pending = ref(false);
//エンドポイント側でエラーがないことを表すテンプレート変数。
const noServerError = ref(true);
//認証が失敗したことを表すテンプレート変数。
const authFailed = ref(false);
//ログインボタンクリック時の処理メソッド。
const onLoginButtonClick = async (): Promise<void> => {
  //ペンディングをtrueに変更。
  pending.value = true;
  //authFailedを初期値に変更。
  authFailed.value = false;
  //noServerErrorを初期値に変更。
  noServerError.value = true;
  //ログインデータのPOST送信。
  const asyncData = await useFetch(
    "/user-management/auth",
    {
      method: "POST",
      body: {
        loginId: loginId.value,
        password: password.value
      }
    }
  );
  //エンドポイント側の処理が成功したならば…
  if(asyncData.error.value == null && asyncData.data.value != null && asyncData.data.value.result == 1) {
    //認証が通ったならば…
    if(asyncData.data.value.token != "" && asyncData.data.value.user != null) {
      //ログインユーザ情報をクッキーに格納。
      const loginUserCookie = useCookie<User|null>("loginUser");
      loginUserCookie.value = asyncData.data.value.user;
      //アクセストークン文字列をクッキーに格納。
      const loginTokenCookie = useCookie<string|null>("loginToken");
      loginTokenCookie.value = asyncData.data.value.token;
      //トップ画面に遷移
      await navigateTo("/");
    }//認証が通らなかった場合…
    else {
      pending.value = false;
      authFailed.value = true;
    }
  } //エンドポイント側の処理が失敗した場合…
  else {
    pending.value = false;
    noServerError.value = false;
  }
};

</script>

<template>
  <h1>ログイン</h1>
  <p v-if="pending">ログイン中…</p>
  <template v-else>
    <p v-if="authFailed">ログインIDまたはパスワードが違います。</p>
    <p v-if="noServerError">IDとパスワードを入力してログインしてください。</p>
    <p v-else>サーバ処理中に障害発生!もう一度ログインを行なってください。</p>
    <form v-on:submit.prevent="onLoginButtonClick">
      <dl>
        <dt>ID</dt>
        <dd><input type="text" v-model="loginId" required></dd>
        <dt>パスワード</dt>
        <dd><input type="password" v-model="password" required></dd>
      </dl>
      <button type="submit">ログイン</button>
    </form>
  </template>
</template>

pages/logout.vue

<script setup lang="ts">
import type {User} from "@/interfaces";

//ログインユーザ情報のクッキーを削除。
const loginUserCookie = useCookie<User|null>("loginUser");
loginUserCookie.value = null;
//アクセストークン文字列のクッキーを削除。
const loginTokenCookie = useCookie<string|null>("loginToken");
loginTokenCookie.value = null;
//ログイン画面に遷移。
await navigateTo("/login");
</script>

components/TheLoggedInSection.vue

<script setup lang="ts">
import type {User} from "@/interfaces";

const loginUser = useCookie<User|null>("loginUser");
</script>

<template>
  <section v-if="loginUser">
    <p>{{loginUser.name}}さんがログイン中</p>
    <p><NuxtLink v-bind:to="{name: 'logout'}">ログアウト</NuxtLink></p>
  </section>
</template>

layouts/character.vue

<template>
  <header>
    <h1>ワンピース!</h1>
  </header>
  <main>
    <h1>キャラクター設定</h1>
    <TheLoggedInSection/>
    <slot/>
  </main>
</template>


ここから先は

2,901字

¥ 100

この記事が気に入ったらサポートをしてみませんか?