2020/05/30

[第4回]Nuxt.js+Auth Moduleでログイン画面を作り込む

vuetifygoogle-drive-api-v3nuxtjs

今回は、本アプリのログイン画面を作成します。
と言ってもapiの実装はまだなの、ここではワイヤーフレームレベルのものになります

以下のような手順で実装していきます。

  1. @nuxtjs/auth をインストールして設定をする
  2. GCPのコンソールから本アプリの設定を作成する
  3. ログインページ用のレイアウトファイルを作成する
  4. ログインページを作成する

note

前回の続きです。
まだご覧になっていない方は、こちらからご覧ください。

Auth Moduleのインストールをしましょう

Auth Moduleとは

FacebookやTwitterでログインに代表されるOAuth2を簡単にNuxt.jsサイトに組み込める @nuxtjs/authモジュールを使っていきます。

Moduleの詳細は以下のページからご覧ください。(本稿では必要最低限のものしか取り扱いません)

Auth Moduleのインストール

"gdrive-manager/client"ディレクトリで以下を実行してインストールします。

% yarn add @nuxtjs/auth

Auth Moduleの設定

client/nuxt.config.jsの編集をします。

  • '@nuxtjs/auth’モジュールを modules に追加しましょう。
  modules: [
    // Doc: https://axios.nuxtjs.org/usage
    '@nuxtjs/axios',
    '@nuxtjs/pwa',
    // Doc: https://github.com/nuxt-community/dotenv-module
    '@nuxtjs/dotenv',
    '@nuxtjs/auth' // ここの行を追加します。
  ],
  • 以下のプロパティを追加して、全てのページで(デフォルトで)認証を必須にします
  router: {
    // See https://auth.nuxtjs.org/guide/middleware.html
    middleware: ['auth']
  },
  • 以下のプロパティを追加して、Authモジュールの設定は完了です
  auth: {
    redirect: {
      login: '/login',
      logout: '/login',
      callback: '/oauth2_callback',
      home: '/'
    },
    strategies: {
      app: {
        _scheme: 'oauth2',
        authorization_endpoint: 'https://accounts.google.com/o/oauth2/auth',
        userinfo_endpoint: `https://www.googleapis.com/oauth2/v3/userinfo`,
        scope: [
          'email',
          'profile',
          'openid',
          'https://www.googleapis.com/auth/drive.metadata.readonly'
        ],
        access_type: undefined,
        access_token_endpoint: undefined,
        response_type: 'token',
        token_type: 'Bearer',
        client_id: process.env.GOOGLE_CLIENT_ID,
        token_key: 'access_token'
      }
    }
  },

注意点

  • 今回、デフォルトで、全てのページに認証が必要な設定を追加しました。個別のページで認証が不要なページには、以下のように “auth:false” プロパティを追加する必要があります
export default {
  auth: false,
}
  • authのプロパティは、サーバー側で認証用のAPIが実装されたら変更していきます。(userinfo_endpointやaccess_token_endpointなどをサーバーのものに変更していきます。)

GCPでアプリの設定をしよう

Googleでログインを実装するために、Google DriveのAPIを有効にする必要が出てきます。
また、セキュリティ的な観点から、GoogleログインのAPIと連携するための設定なども必要になってきます。

それには、GCPにログインし、専用のプロジェクトおよび認証アプリの設定をする必要があります。

GCPプロジェクトを作成しましょう

GCPにログインしてください

ログイン後、プロジェクトを作成します。

  • 新しいプロジェクト」ボタンをクリックして作成していきます
  • プロジェクト名は適当なもので大丈夫です

1-gcp-project-1-min.png

2-gcp-project-2-min.png

Google Drive APIを有効にしましょう

https://console.cloud.google.com/apis/libraryここからGoogle Drive APIを検索して
APIを有効化します。

3-enable-gdrive-api-1-min.png

4-enable-gdrive-api-2-min.png

認証情報を作成しましょう

APIとサービス > 認証情報のメニューから作成します。

5-gcp-app-1-min.png

6-gcp-app-2-min.png

認証情報を作成 > OAuthクライアントID を作成します。
最初に「同意画面」を作成する必要があるようなので、そちらから作成していきます。

  • 以下の項目を設定して、OAuth同意画面を作成しましょう。
名前 設定値 メモ
User Type 外部 or 内部 基本的には内部がおすすめですが、GSuiteを使ってない場合は外部しか選択できません。(どちらでも良いでしょう。)
アプリケーション名 GDrive Manager お好きな名前をどうそ
アプリケーションのロゴ - お好きな画像をどうぞ
サポートメール - 選択できるものを選びましょう
スコープ email, profile, openid, https://www.googleapis.com/auth/drive.metadata.readonly drive.metadata.readonlyで検索して、追加しましょう
認証済みドメイン いったんは空欄でOKです
[アプリケーション ホームページ] リンク いったんは空欄でOKです
[アプリケーション プライバシー ポリシー] リンク いったんは空欄でOKです
[アプリケーション利用規約] リンク いったんは空欄でOKです
  • 以下の項目を設定して、OAuthクライアントIDを作成しましょう。
名前 設定値 メモ
アプリケーションの種類 ウェブ アプリケーション
名前 GDrive Manager お好きな名前をどうそ
認証済みのJavaScript生成元 http://localhost:3000 Nuxt.jsの起動画面
認証済みのリダイレクトURI http://localhost:3000/oauth2_callback callback画面(後ほど実装します)

作成したら、以下画面に表示されますので、メモしておきましょう

  • クライアントID
  • クライアントシークレット(こちらは実際には使いません)

そして、メモしたクライアントIDを ".env"ファイルに追記しましょう
(ファイルがなければ追加しましょう。)

client/.env

GOOGLE_CLIENT_ID=xxxxxxxxxxxx-yyyyyyyyyyyyyyyyy.apps.googleusercontent.com

最後に、.envをnuxt.config.jsで利用するために以下の行を追加しましょう。

client/nuxt.config.js

  • 以下をファイルの先頭に追加します
import dotenv from 'dotenv'
dotenv.config()

以上で、設定は終わりです。こちらの内容を使って、ログイン画面を作り込んでいきましょう。

ログインページ用のレイアウトを作成しよう

前回、デフォルトレイアウトを作成しましたが、ログイン画面には使いません。
以下のファイルを追加してみましょう。

client/layouts/centered.vue

<template>
  <v-app dark>
    <v-content class="grey lighten-5">
      <v-container class="fill-height" fluid>
        <nuxt />
      </v-container>
    </v-content>
  </v-app>
</template>
  • アプリケーションバーやサイドナビゲーションなどがない、コンテンツを中央よせにしたレイアウトになっています。

ログインページを作成しましょう

ログインに必要なページは主に2つです。

  • client/pages/login.vue : ログインボタンが配置されたページ
  • client/pages/oauth2_callback.vue : Googleログインからリダイレクトされるページ
  • client/pages/home.vue: ログイン後に表示されるページ

それぞれ以下のようになります

client/pages/login.vue

<template>
  <v-row align="center" justify="center">
    <v-col cols="12" sm="8" md="6" lg="4">
      <v-card class="elevation-12">
        <v-toolbar color="primary" flat>
          <v-toolbar-title>GDrive Manager</v-toolbar-title>
          <v-spacer />
        </v-toolbar>
        <v-card-actions>
          <v-spacer></v-spacer>
          <v-btn
            color="secondary"
            large
            class="mr-2 mb-2"
            @click.stop="authenticate"
            >Login with Google</v-btn
          >
        </v-card-actions>
      </v-card>
    </v-col>
  </v-row>
</template>

<script>
export default {
  auth: false,
  layout: 'centered',
  methods: {
    authenticate() {
      this.$auth.loginWith('app')
    }
  }
}
</script>

ポイントとしては以下になります。

  • このページの表示は認証不要なので、"auth: false"を指定します。
  • レイアウトを先ほど作成した、"centered"のものを指定します。(指定しないとdefaultのレイアウトが使われてしまいます。)
  • "Login with Google"ボタンを押すと “$auth.loginWith(‘app’)” を呼ぶようにします。

client/pages/oauth2_callback.vue

<template>
  <v-row justify="center">
    <v-col cols="12" md="8">
      <v-skeleton-loader
        class="mx-auto mt-12"
        type="card,list-item-three-line,list-item-three-line,list-item-three-line,actions"
      ></v-skeleton-loader>
    </v-col>
  </v-row>
</template>

<script>
export default {
  auth: false,
  mounted() {
    if (this.$auth.loggedIn) {
      this.$router.push('/home')
    }
  }
}
</script>

ポイントとしては以下になります。

  • homeページに移動するまでは、v-skelton-loaderを使って、読み込み中をきれいに見せます。
  • ページ表示時に、ログインしていたらhomeページに移動するようにしておきます。

client/pages/home.vue

<template>
  <v-row justify="center">
    <v-col cols="12" md="8">
      <p class="display-1">{{ title }}</p>
    </v-col>
  </v-row>
</template>

<script>
export default {
  data() {
    return {
      title: 'Home'
    }
  }
}
</script>

また、前回中途半端だったログアウト処理を修正します。

client/layouts/default.vue

  methods: {
    avatarMenuItemClick(href) {
      switch (href) {
        case '/logout':
          // window.alert('TODO implement logout') <- この行を削除して
          // 以下の2行を追加します。
          this.$auth.logout()
          this.$auth.redirect('login')
          break
        default:
          this.$router.push(href)
          break
      }
    }
  }

さらに、topページの認証部分を修正します。

client/pages/index.vue

最終的に以下のように修正します。

<template>
  <v-row justify="center">
    <v-col cols="12" md="8">
      <p class="display-1">{{ title }}</p>
    </v-col>
  </v-row>
</template>

<script>
export default {
  auth: false,
  data() {
    return {
      title: 'GDrive Manager'
    }
  },
  mounted() {
    if (this.$auth.loggedIn) {
      this.$router.push('/home')
    } else {
      this.$router.push('/login')
    }
  }
}
</script>

ポイントとしては以下になります。

  • "auth: false"を追加して、認証不要のページに設定します。
  • mountedを追加して、ページ表示時にログインされていたらhomeへそうでなければloginへリダイレクトするようにします。

設定&実装はおしまいです。では動作確認をしてみましょう。

  • 以下を実行してサーバーを起動します。
% yarn run dev
  • http://localhost:3000にアクセスしましょう。ログイン画面が表示されるはずです。

7-login-min.png

  • ログインボタンを押し、実際にGoogleアカウントでログインしましょう。

  • 初回ログイン時は以下のようなエラーとも取れる警告画面が出てきます。(外部向けのアプリケーションとして作成している場合は、このような画面が出るでしょう。)

8-after-google-login-min.png

  • 詳細をクリックして、続行することができます。

9-grant-gdrive-access-min.png

  • 認証を済ませるとHome画面にくれば成功です。

10-home-min.png

今回はこれで以上になります。

今回作成したファイルは GithubのPull Request からもご覧いただけます。

次回は、Home画面のワイヤーフレーム実装を中心に解説していきます。