HOME  >  Web開発 >  【Nuxt.js + Auth認証】Nuxt.jsでAuth認証を実装する

Web開発

【Nuxt.js + Auth認証】Nuxt.jsでAuth認証を実装する

【Nuxt.js + Auth認証】Nuxt.jsでAuth認証を実装する

目次

  1. 実装の準備
    1. Nuxtプロジェクトの作成
    2. nuxtjs/authのインストールと設定
  2. auth認証の実装
    1. ログインフォーム作成
    2. Tokenの確認
    3. ログイン状態の確認
    4. ユーザー情報を取得
    5. ログアウト処理の実装
    6. ユーザー登録機能の実装
    7. ページにアクセス制限をかける
  3. まとめ

今回は、Nuxt.jsの認証モジュールであるnuxtjs/authを使って、Auth認証の設定を行い、認証機能を実装して行こうと思います。

バックエンド側の処理は前回まとめた記事のものを使っていこうと思います。

先に下記記事を読むことをお勧めします。

【Express + JWT】ExpressでJWTを使った認証機能を作る
https://www.dailyupblog.com/backend_development/1117/

それではいきましょう。

実装の準備

Nuxtプロジェクトの作成

まず、認証機能アプリケーションを作るために、Nuxt.jsのプロジェクトを作成しましょう。

任意のディレクトリに「nuxt-auth」というディレクトリを作成して、cdコマンドでこのディレクトリ内に移動しておきましょう。

そこで下記コマンドを実行して、プロジェクトを作成してください。

途中で聞かれる質問はお好みで設定してください。

npx create-nuxt-app

すると、データ一式が生成されるので、これでOKです。

下記コマンドを実行して、nuxt.jsを起動しましょう。

//npmの場合
npm run dev

//yarnの場合
yarn dev

その後、ブラウザで「http://localhost:3000」にアクセスして、下記画面が表示されたらOKです。

nuxtjs/authのインストールと設定

さて、今回使うnuxtjs/authのパッケージをインストールしましょう。

下記コマンドでnpmもしくはyarnでインストールします。

また、今回http通信もするので、「axios」もインストールしておきましょう。

//npmの場合
npm install axios @nuxtjs/auth

//yarnの場合
yarn add axios @nuxtjs/auth

そしたら、nuxt.config.jsを開きましょう。

このファイルの中に下記のように追記してください。

export default {
  // Global page headers: https://go.nuxtjs.dev/config-head
  head: {
    title: "nuxt-auth",
    htmlAttrs: {
      lang: "en",
    },
    meta: [
      { charset: "utf-8" },
      { name: "viewport", content: "width=device-width, initial-scale=1" },
      { hid: "description", name: "description", content: "" },
    ],
    link: [{ rel: "icon", type: "image/x-icon", href: "/favicon.ico" }],
  },

  // Global CSS: https://go.nuxtjs.dev/config-css
  css: ["element-ui/lib/theme-chalk/index.css"],

  // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
  plugins: ["@/plugins/element-ui"],

  // Auto import components: https://go.nuxtjs.dev/config-components
  components: true,

  // Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
  buildModules: [
    // https://go.nuxtjs.dev/typescript
    "@nuxt/typescript-build",
  ],

  // Modules: https://go.nuxtjs.dev/config-modules
  modules: ["@nuxtjs/axios", "@nuxtjs/auth"],  //追記

  // Build Configuration: https://go.nuxtjs.dev/config-build
  build: {
    transpile: [/^element-ui/],
  },

  //追記
  axios: {
    baseURL: "http://localhost:5000/",
  },

  //追記
  auth: {
    strategies: {
      local: {
        endpoints: {
          login: {
            url: "/auth/login",
            method: "post",
            propertyName: "token",
          },
          logout: {
            url: "/auth/logout",
            method: "post",
          },
          user: {
            url: "/auth/user",
            method: "get",
            propertyName: "user",
          },
        },
      },
    },
  },
}

axiosとnuxtjs/authのモジュール情報の追記と、axiosとnuxtjs/authの設定を追記します。

axiosはbaseURLにサーバーのURL(http://localhost:5000/)を設定しておきます。

nuxtjs/authは、サーバー側にアクセスする設定をこのnuxt.config.js内にエンドポイントとして追記します。

とりあえず、nuxt.js/authのドキュメントに記述されている内容を最初はコピー&ペーストして使います。

nuxt.js/authのドキュメント
https://auth.nuxtjs.org/schemes/local/#usage

最後に、今回使うnuxtjs/authはVuexを利用しているため、「store」ディレクトリ内にファイルがないと、実行時にエラーが起きるため、「store」内にindex.jsファイルを作成しておきましょう

ファイルの中身は空で大丈夫です。

また、今回axiosでhttp通信を行うのですが、クライアント側のポート「3000」に対して、バックエンド側のポートが「5000」なので、このままだとCORSポリシー違反となり、エラーになってしまいます。

これを防ぐために、corsパッケージをインストールする必要があります。

下記記事にやり方載っているので、この通りにインストールと設定を行なってください。

【Nuxt.js + Express】Expressで開発したAPIをNuxt.jsで実行する〜取得 – Expressにcorsを導入する
https://www.dailyupblog.com/web_development/1078/#chapter-3

ここまででnuxtjs/authのインストールと設定は完了です。

auth認証の実装

ログインフォーム作成

ここまで準備が完了したら、早速ログインフォームを作ってみましょう。

「pages」ディレクトリ内にログイン用のページとして、login.vueを作成してください。

このファイル内に下記のように記述しましょう。

※今回は特にElementなどのUIライブラリは使いません。

<template>
  <div class="container">
    <div>
      <h1>ログインする</h1>
      <form @submit.prevent="userLogin">
        <div>
          <label for="email">メールアドレス:</label>
          <input type="email" v-model="form.email" />
        </div>
        <div>
          <label for="password">パスワード:</label>
          <input type="password" v-model="form.password" />
        </div>
        <div>
          <button type="submit">ログイン</button>
        </div>
      </form>
    </div>
  </div>
</template>

<script>
import Vue from "vue";
export default Vue.extend({
  data () {
    return {
      form: {
        email: "",
        password: ""
      }
    }
  },
  methods: {
    userLogin () {
      this.$auth.loginWith('local', {
        data: this.form
      })
    }
  }
});
</script>

<style scoped>
.container {
  margin: 0 auto;
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}
h1 {
  margin-bottom: 0.7em;
}
form > * {
  margin-bottom: 4%;
}
</style>

templateには入力フォームを記述しましたが、送信ボタンを押した際に、送信されて欲しくないので、「@submit.prevent」を設定して送信を無効にし、userLogin関数が実行されるようにします。

「メールアドレス」と「パスワード」を入力するようにしましょう。

data()には、「email」と「password」を設定しておきましょう。

methodにはuserLogin関数を記述します。

内容は、this.$auth.loginWith関数を使い、引数に送信するuser情報を設定するだけで完了です。

送信先はnuxt.config.js内に設定した「login」のurlになります。

    userLogin () {
      this.$auth.loginWith('local', {
        data: this.form
      })
    }

ここまでできたら、ログイン後、受け取ったuser情報でログインして返ってくるユーザー情報をexpress側のコンソールに出力したいので、console.logを追記しましょう。

前回作った、express側のデータの「routes」ディレクトリ内のindex.jsを開きログインAPIの中に下記のように追記しましょう。

//・・・省略
//ログインAPI
router.post("/auth/login", function (req, res, next) {
  const { email, password } = req.body;
  pool.query("SELECT * FROM users WHERE email = $1", [email], function (
    error,
    user
  ) {
    if (error) {
      res.status(400).json({
        status: "400 Bad Request",
        error: error,
      });
    }
    if (user.rowCount === 0) {
      return res.json({
        message: "email not found",
      });
    }
    bcrypt.compare(password, user.rows[0].password, function (error, results) {
      if (error) {
        return res.status(400).json({
          error: error.message,
        });
      }
      if (!results) {
        return res.json({
          message: "password is not correct",
        });
      }
      console.log(user.rows[0]); //追記
      //Tokenの発行
      const payload = {
        id: user.rows[0].id,
        name: user.rows[0].name,
        email: user.rows[0].email,
      };
      const token = jwt.sign(payload, "secret");
      return res.json({ token });
    });
  });
});
//・・・省略

ここまでできたら、expressとnuxt両方を起動して、ブラウザで「http://localhost:3000/login」にアクセスしましょう。

下記のような画面が出るはずです。

既に登録されているユーザーのメールアドレスとパスワードを入力して、「ログイン」ボタンを押してください。

ページ上では画面がhomeに遷移しますが、特に変わったことは起きません。

しかし、expressを実行しているコマンドラインを確認してください。

すると、下記のようにユーザー情報が表示されます。

そうしたら成功です。

Tokenの確認

続いて、ログイン後にエンドポイントで設定したTokenの確認についてです。

nuxt.config.jsに記載ある通り、ユーザー認証後にuserのURLである「/auth/user」にアクセスして、ユーザー情報を取得します。

//・・・省略
          user: {
            url: "/auth/user",
            method: "get",
            propertyName: "user",
          },
//・・・省略

今回は動作を試すために、ヘッダーを確認し、Tokenが正しく含まれているか確認してみましょう。

express側のデータを少しいじります。

「express-auth」の「routes」>index.jsを開きましょう。

「Tokenの確認」の項目に追記します。

下記のように追記してください。

//・・・省略
//Tokenの確認
router.get("/auth/user", (req, res) => {
  const headers = req.headers; //追記
  console.log(headers); //追記
  const bearToken = req.headers["authorization"];
  const bearer = bearToken.split(" ");
  const token = bearer[1];

  jwt.verify(token, "secret", (error, user) => {
    if (error) {
      return res.sendStatus(403);
    } else {
      return res.json({
        user,
      });
    }
  });
});
//・・・省略

expressを起動し直し、ブラウザで「http://localhost:3000」にアクセスしましょう。

そして、試しに「スティーブ」の情報でログインしてみましょう。

下記のようにexpress側のコンソール上に情報が表示されたら成功です。

この際、「authorization」の項目にToken情報が記述されていたら問題ないです。(※下記赤枠)

ログイン状態の確認

さて、Tokenによってuser情報を取得した後は、「$auth」を使うことで、ログイン状態やユーザー情報にアクセスが可能です。

まず、ログイン状態は「$auth.loggedIn」で確認が可能です。

簡単ですね。

「pages」フォルダ内のindex.vueを開いて、下記のように記述しましょう。

<template>
  <div class="container">
    <div>
      <h1>Auth認証アプリケーション</h1>
      <p>ログイン状態:{{$auth.loggedIn}}</p>
    </div>
  </div>
</template>

<script lang="ts">
import Vue from "vue";

export default Vue.extend({});
</script>

<style>
.container {
  margin: 0 auto;
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
}

.title {
  font-family: "Quicksand", "Source Sans Pro", -apple-system, BlinkMacSystemFont,
    "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  display: block;
  font-weight: 300;
  font-size: 100px;
  color: #35495e;
  letter-spacing: 1px;
}

.subtitle {
  font-weight: 300;
  font-size: 42px;
  color: #526488;
  word-spacing: 5px;
  padding-bottom: 15px;
}

.links {
  padding-top: 15px;
}
</style>

下記の箇所でログイン状態を出力します。

試してみましょう。

まず、ログインしていない状態で「http://localhost:3000」にブラウザでアクセスしてみてください。

そうすると、下記のように「false」が表示されているはずです。

そうしたら、今度は「http://localhost:3000/login」に移動して、ログインしてみてください。

その後、TOPに移動すると下記のように「true」になっているのが分かります。

$authを使って簡単にログイン状態が確認できました。

ユーザー情報を取得

さて、ログイン状態の次はユーザー名だったり、メールアドレスだったりのユーザー情報を取得します。

ユーザー情報を取得するには、「$auth.user」で確認ができます。

まず、ログイン後に遷移するダッシュボードページを作ってあげましょう。

ダッシュボードページを作る前に、ログイン後にこのページに遷移するように、nuxt.config.jsで設定を記述しましょう。

//・・・省略
  auth: {
  //追記
    redirect: {
      home: "/dashboard",
    },
    strategies: {
      local: {
        endpoints: {
          login: {
            url: "/auth/login",
            method: "post",
            propertyName: "token",
          },
          logout: {
            url: "/auth/logout",
            method: "post",
          },
          user: {
            url: "/auth/user",
            method: "get",
            propertyName: "user",
          },
        },
      },
    },
  },
//・・・省略

リダイレクト先を「home:”/dashboard”」に設定してあげます。

これでOKです。

続いて、「pages」フォルダ内にdashboard.vueを作成して、下記のように記述しましょう。

<template>
  <div class="container">
    <div>
      <h1>ダッシュボード</h1>
      <p>ログイン状態:{{$auth.loggedIn}}</p>
      <p>ユーザー名:{{$auth.user.name}}</p>
      <p>メールアドレス:{{$auth.user.email}}</p>
    </div>
  </div>
</template>
<script>
import Vue from "vue";
export default Vue.extend({
  data () {
    return {}
  }
});
</script>

<style scoped>
h1 {
  text-align: center;
  margin-bottom: 5%;
}
p {
  margin-bottom: 3%;
}
.container {
  margin: 0 auto;
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}
</style>

全て{{$auth.user}}を使ってユーザー情報を出力しています。

それでは試しにブラウザから「http://localhost:3000」にアクセスして、ログインしてみましょう。

下記のようにダッシュボードページにリダイレクトして、ログイン状態とユーザー情報が表示されているはずです。

ログアウト処理の実装

ログインができたら、次はログアウトする処理を実装しましょう。

ログアウトも非常に簡単で、「$auth.logout()」を実行することで実現できます。

ログアウトの際は、ブラウザのLocal storage*とcookie*に保存されているTokenを削除します。

*Local storageとcookieはどちらともブラウザに情報を保持することができる保管場所のようなところです。基本的にLocal storageやcookieにTokenは保存されます。詳しくは以下をご参照ください。

【サンプル付き】Local Storageとは?使い方を詳しく解説
https://webliker.info/how-to-use-localstrage/
初心者でもわかる『Cookie(クッキー)』講座 危険性やスマホでの設定方法もズバリ解説
https://time-space.kddi.com/ict-keywords/20180726/2392

さて、今回はダッシュボードページにログアウトボタンを実装しましょう。

dashboard.vueを開いて、下記のように記述してください。

<template>
  <div class="container">
    <div>
      <h1>ダッシュボード</h1>
      <p>ログイン状態:{{$auth.loggedIn}}</p>
      <p>ユーザー名:{{$auth.user.name}}</p>
      <p>メールアドレス:{{$auth.user.email}}</p>
      <div v-if="$auth.loggedIn">
        <button @click="$auth.logout()">ログアウト</button>
      </div>
    </div>
  </div>
</template>
//・・・省略

下記の箇所を追記しました。

      <div v-if="$auth.loggedIn">
        <button @click="$auth.logout()">ログアウト</button>
      </div>

クリックイベントで「$auth.logout()」を実行するようにしました。

さて、ログアウト後に再度ログインページへリダイレクトをかけたいので、nuxt.config.jsを開いて、下記のように追記しましょう。

//・・・省略
  auth: {
    redirect: {
      home: "/dashboard",
      logout: "/login", //追記
    },
    strategies: {
      local: {
        endpoints: {
          login: {
            url: "/auth/login",
            method: "post",
            propertyName: "token",
          },
          logout: false,
          user: {
            url: "/auth/user",
            method: "get",
            propertyName: "user",
          },
        },
      },
    },
  },
//・・・省略

ここまでできたら、ブラウザでログインページへアクセスして、ログインしてみましょう。

下記のようにログアウトボタンが設置されているはずです。

その後、ログアウトボタンをクリックして、ログアウトしてみましょう。

再度ログインページへリダイレクトされたら、成功です。

さらに、Google chromeのディベロッパーツールの「application」から「cookie」と「Local storage」を確認するとちゃんとTokenが削除されていることが分かります。

ユーザー登録機能の実装

続いて、ユーザー登録機能の実装をしていきます。

早速、登録ページを作成します。

「pages」フォルダ内にregister.vueファイルを作成し、下記のように記述してください。

<template>
  <div class="container">
    <div>
      <h1>登録する</h1>
      <form @submit.prevent="registerUser">
        <div>
          <label for="name">名前:</label>
          <input type="text" v-model="user.name" />
        </div>
        <div>
          <label for="email">メールアドレス:</label>
          <input type="email" v-model="user.email" />
        </div>
        <div>
          <label for="password">パスワード:</label>
          <input type="password" v-model="user.password" />
        </div>
        <div>
          <button type="submit">登録</button>
        </div>
      </form>
    </div>
  </div>
</template>

<script>
import Vue from "vue";
export default Vue.extend({
  data () {
    return {
      user: {
        name: "",
        email: "",
        password: ""
      }
    }
  },
  methods: {
    registerUser () {
      this.$axios.post('/auth/register/', this.user).then((res) => {
        this.$auth.loginWith('local', {
          data: this.user
        })
      })
    }
  }
});
</script>

<style scoped>
.container {
  margin: 0 auto;
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}
h1 {
  margin-bottom: 0.7em;
}
form > * {
  margin-bottom: 4%;
}
</style>

<template>内には登録フォームを記述します。

「名前」「メールアドレス」「パスワード」の三つの情報を入力させるようにし、それぞれv-modelにデータをセットします。

formタグには、ログインフォームの時と同じように「@submit.prevent」を設定し、送信できないようにし、その代わりregisterUser関数を実行するようにします。

registerUser関数は、axios通信を使って、もともとexpressで作っておいたユーザー登録APIである「/auth/register/」を実行するようにします。

そしてその後、登録に成功したら、$auth.loginWith関数を使って、ログインするようにしてあげましょう。

    registerUser () {
      this.$axios.post('/auth/register/', this.user).then((res) => {
        this.$auth.loginWith('local', {
          data: this.user
        })
      })
    }

ここまでできたら、挙動確認しましょう。

ブラウザで「http://localhost:3000/register」にアクセスすると下記のような登録ページが表示されます。

新たにユーザーを登録してみましょう。

3つの情報を入力後、「登録」を押したら、ユーザー情報が登録され、ログインされて、ダッシュボードページへ遷移するはずです。

データベースを確認したら、登録したユーザーの情報がテーブルに追加されていることでしょう。

ページにアクセス制限をかける

最後にページにアクセス制限をかける方法をご紹介します。

ログインしていないユーザーに見せたくないページなどがあると思います。

そういったページに制限をかけることで、見せないようにすることが可能です。

今回はdashboardページがログイン後に入れるページになるので、このページにアクセス制限をかけてみたいと思います。

やり方は非常に簡単で下記のように追記するだけです。

//・・・省略
export default Vue.extend({
  middleware: "auth",
//・・・省略

ミドルウェアを使って設定します。

これだけで実装可能なので、非常に簡単ですね。

この状態で、ブラウザで「http://localhost:3000/dashboard」にアクセスしてみると、「/login」ページへリダイレクトされます。

まとめ

今回は、前回expressで作ったJWT認証を、Nuxt.jsのauthモジュールを使って、クライアント側で認証機能を実装するといったことをやってみました。

authモジュールをインポートするだけでこんなにも簡単に認証機能を実装できるのです。

このモジュールを使えば、いわゆるユーザー登録型のアプリケーションを作ることができますので、より極めていきたいところです。

特に、今回触れなかったセキュリティについてはまた別の機会にやりたいと思います。

それでは今回はここまで。

お疲れ様でした。

関連記事

関連記事