Works by

Ren's blog

アプリケーションバックエンド中心に書いていきます

【Firebase】Firebase(+Vue.js)でWebアプリケーション上に認証を実装する

f:id:rennnosukesann:20181216205841p:plain

Frebaseとは

Firebaseは、Googleが提供するモバイルアプリケーション開発のプラットフォームサービスです。mBaas(Mobile Backend as a Service) とも呼ばれ、モバイルアプリケーションのバックエンド機能を提供します。例えばアプリケーションの構築に必要なネットワークやストレージ、サーバといったインフラ基盤や、後述する認証や永続化ロジックなどといったバックエンド機能をFirebaseが提供してくれます。

Firebaseの何がいいのか

Firebaseを使うことで、上記のようなインフラ/バックエンドの機能をFirebaseに任せることができ、アプリエンジニアはフロントの実装に集中することができます。

例えばインフラ面では、特にサーバーの立ち上げ作業などを行うことなく、Firebaseが提供する環境にアプリをそのままデプロイすることができます。またアプリの監視や分析なども、Firebase内のサービスで提供されています。

バックエンド面としてもFirebaseのサポートは厚く、例えばストレージサービスも含めた認証の仕組みを持っており、フロントエンドはAPIコールだけで認証ロジックを実装することができます。認証は実装に手間がかかるだけではなく、自前実装によるバグの混入によってセキュリティリスクにもなりえるので、こういったサポートはとても嬉しいですね。もちろん認証後のトークンIDの運用などもあるので、セキュリティリスクがゼロになるわけではないのですが・・・。

このように、フロントエンド開発したいけどバックエンド実装に時間がかけれられない、インフラの知識に自信がない・・・といった方でも、手早くサービスを立ち上げることができる強力なサービスです。アプリリリースまでのスピード感を特に重視されている方にとって、大きな味方となってくれることでしょう。

Firebaseとブラウザベースアプリケーション

Firebaseはモバイルアプリを対象に作られている節がありますが、ブラウザで動作することが前提のWebアプリでも使用することはできます。Firebaseは、ブラウザベースのモバイルアプリも想定してSDKを提供してくれています。

FirebaseでWebアプリケーション上にベーシック認証機能を実装する

Firebaseの提供する認証機能を使って、実際にブラウザ上アプリでの認証機能を実装してみましょう!

SDKの導入

はじめに、Firebaseの提供するAPIを使用するためのSDKを導入します。

firebase.google.com

Firebase公式のページの「スタートガイド」ボタンをクリックします。

f:id:rennnosukesann:20181217201021p:plain

このとき、Googleアカウントにログインしていない場合ログイン画面が表示されるので、自分のGoogleアカウントにログインしましょう。

f:id:rennnosukesann:20181217203028p:plain

次のページではFirebase上に作成したプロジェクト一覧が表示されます。 今回は初めてなので、下図のようなアイコンをクリックして新規にプロジェクトを作成していきます。

f:id:rennnosukesann:20181217200327p:plain

プロジェクト追加ダイアログが表示されます。 プロジェクト名を入力し、「測定管理者間のデータ保護条項に同意します。...」のチェックボックスにチェックを入れます。 これは少し前に有名になったGDPRに係る条項です。「「Google のサービス」のデータ共有設定」を無効にすれば、ここの条項に同意してもデータ提供を拒否することができます(ですが上のチェックマークに関しては、チェックが必須のようです)。

プロジェクト名を入力しチェックをつけおわったら、「プロジェクトを作成」ボタンをクリックします。

f:id:rennnosukesann:20181217200910p:plain

下のようなダイアログが出てくるので、しばらく待ちます。

f:id:rennnosukesann:20181217200649p:plain

ダイアログが下のようになったら、プロジェクト作成完了です。 「次へ」ボタンを押して、次に進みます。

f:id:rennnosukesann:20181217201118p:plain

以下のようなダッシュボード画面が表示されたら完了です。

アプリの認証機能を実装する

次に、アプリのコードを書いていきます!

プロジェクトの作成

今回はVue.jsを使ってフロントエンドアプリを構築していきます。 下記記事を参考に、プロジェクトを作成してください。

rennnosukesann.hatenablog.com

以降、上記記事で作成したプロジェクト上での開発を前提とします。

プロジェクトの認証機能を有効にする

先程開いたダッシュボードで認証機能を有効にする設定を行います。

ダッシュボード画面の「認証」のカードをクリックするか、右側メニューの「Authentication」をクリックします。

f:id:rennnosukesann:20181219202506p:plain

f:id:rennnosukesann:20181219202552p:plain

すると認証に関する設定画面が開くので、画面中の「ログイン方法を設定」をクリックします。

f:id:rennnosukesann:20181219202742p:plain

すると許可するログイン方法の設定一覧が開くので、「メール/パスワード」の項目の編集アイコンをクリック。

f:id:rennnosukesann:20181219202835p:plain

「有効にする」スイッチをONにし、「保存」をクリック。

f:id:rennnosukesann:20181219202909p:plain

これでメールアドレスとパスワードによる認証が実装可能になりました。

Firebase SDKをインストールする

WebアプリケーションでFirebase API を使用する方法は主に2つあります。

  • HTML上でCDN経由でSDKjs ファイルをインポートする
  • npm yarn などのパッケージ管理システム経由でSDKパッケージをインストールする

今回は npm 経由でインストールを行います。

作成したプロジェクトディレクトリに移動し、npm install firebase を実行してください。

$ cd [作成したプロジェクトへのパス]
$ npm install firebase --save

これでプロジェクトにSDKがインストールされました!

アプリケーション上にアカウント登録画面を作成する

「プロジェクトの作成」の項で作成したプロジェクトは、最初からデプロイ可能な状態となっています。というわけで、一旦アプリをデプロイしてみましょう!

# 作成したプロジェクト上で
$ npm run serve

するとVueのボイラーテンプレートアプリが起動します。

f:id:rennnosukesann:20181218224212p:plain

ここに新しく認証画面を追加してみましょう!

1. Firebase初期化処理の追加

まず、作成したプロジェクト中の src/main.ts を以下のように編集します。

src/main.ts
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';

// ここから追加
import firebase from 'firebase';

// firebase初期化
const config = {
  apiKey: "<API_KEY>",
  authDomain: "<PROJECT_ID>.firebaseapp.com",
  databaseURL: "https://<DATABASE_NAME>.firebaseio.com",
  projectId: 'XXXXXXXXXX',
  storageBucket: "<BUCKET>.appspot.com",
  messagingSenderId: 'XXXXXXXX',
};
firebase.initializeApp(config);

// ここまで追加

Vue.config.productionTip = false;

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

追加した箇所のうち const config = ... からの部分はアプリの設定情報が書かれています。これはダッシュボード画面中央の </> アイコンから参照できます。

f:id:rennnosukesann:20181217202237p:plain

f:id:rennnosukesann:20181217204348p:plain

<script> タグ内の記述をコピーし、 上記コードのように main.ts に貼り付けてください。

f:id:rennnosukesann:20181217202303p:plain

2. サインアップ画面の作成

次に、サインアップ画面部分のコードを作成していきます。 Vue.jsは、アプリの画面を構成する部品を「UIコンポーネント」として扱います。 UIコンポーネントはUI、いわゆる画面表示上の要素と、それに紐づくロジックのまとまりです。Vue.jsでは画面表示を定義するコード(主にHTML) と画面表示に紐づくロジックを定義するスクリプト(主にJavaScriptやTypeScriptなど)、そして画面定義に対するスタイル定義(CSSなど)を .vue ファイルとして一箇所に定義でき、それをUIコンポーネント単位でそれぞれ記述することができます。

それでは、サインアップ画面のUIコンポーネント src/views/Auth.vue を作成していきましょう。

本当は再利用性・保守性などを考えつつ、画面を意味のある単位に分けてUIコンポーネントとして作成していくのですが、今回は簡単のため一画面丸々UIコンポーネントとして作成します。

src/views/Auth.vue
<template>
  <div class="auth">
    <p>Sign Up</p>
    <input v-model="email" placeholder="E-mail">
    <input type="password" v-model="password" placeholder="password">
    <div class="button" @click="signup">Sign Up</div>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import firebase from 'firebase';

@Component
export default class Auth extends Vue {

  private email: string = '';
  private password: string = '';

  private signup() {
    firebase
      .auth()
      .createUserWithEmailAndPassword(this.email, this.password)
      .then(() => {
        alert('Success to Sign Up!');
      })
      .catch((error) => {
        alert('Failed to Sign Up...\n error code : ' + error.code + ', error message : ' + error.message);
      });
  }
}
</script>

<style lang="scss">

.auth {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.auth input {
  width: 200px;
  height: 30px;
  margin: 10px;
  padding: 0 10px;
  border: solid 1px #999999;
  border-radius: 5px;
}

.auth .button {
  width: 80px;
  height: 30px;
  margin: 10px;
  padding: 7px 0 0 0;
  color: white;
  background-color: #999999;
  border-radius: 5px;
}

.auth .button:hover{
  opacity: 0.5;
  cursor: pointer;
}

</style>
UI部分

src/views/Auth.vue のうち、画面定義、すなわちViewに該当する部分が以下になります。メールアドレス・パスワードの入力欄と、Signupボタンを一つ用意しています。 v-model は「ディレクティブ」と呼ばれるVueの機能の一つで、ロジック中の変数にビューへの入力をバインドします。ここでは Auth クラスの email password にそれぞれの入力欄に入力された値が紐付いています。 button にはイベントハンドラとして Auth クラスのメソッド signup() が設定されています。

<template>
  <div class="auth">
    <p>Sign Up</p>
    <input v-model="email" placeholder="E-mail">
    <input type="password" v-model="password" placeholder="password">
    <div class="button" @click="signup">Sign Up</div>
  </div>
</template>

ロジック部分

画面定義部分の下には内部ロジックのスクリプトが記述されています。 注目していただきたいのは、 class Auth のメソッド signup() です。こちらのメソッドはSignupボタンのクリックイベントハンドラとなっています。このメソッドではFirebase SDKのモジュールである firebase を参照して、ユーザ登録用のAPIを呼び出しています。

ユーザ登録に必要な処理はたったこれだけです。firebase.().auth().createUserWithEmailAndPassword() メソッドをメールアドレス・パスワードを渡して呼び出すと、 非同期に認証処理を実行します。このメソッドからは Promise オブジェクトが返ってくるので、 then() に成功時処理を、 catch に失敗時処理を渡すことができます。

    firebase
      .auth()
      .createUserWithEmailAndPassword(this.email, this.password)
      .then(() => {
        alert('Success to Sign Up!');
      })
      .catch((error) => {
        alert('Failed to Sign Up...\n error code : ' + error.code + ', error message : ' + error.message);
      });

2. Auth.vue動線の追加

UIコンポーネントを作成したら、今度はこのUIコンポーネントを表示するための動線を作成します。

src/router.ts を以下のように編集します。

src/router.ts
import Vue from 'vue';
import Router from 'vue-router';
import Home from './views/Home.vue';
import Auth from './views/Auth.vue';

Vue.use(Router);

export default new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home,
    },
    {
      path: '/about',
      name: 'about',
      // route level code-splitting
      // this generates a separate chunk (about.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import(/* webpackChunkName: "about" */ './views/About.vue'),
    },
// ここから追加
    {
      path: '/auth',
      name: 'auth',
      component: Auth,
    },
// ここまで追加
  ],
});

src/router.ts はアプリのルーティング情報、すなわちどのパスに遷移したらどのページを表示するか、といった部分を制御します。 今回は /auth パスを追加し、ページ遷移時には src/view/Auth.vue で定義した内容を表示するようにしました。

これでアドレスバーに [アプリのベースパス]/auth を追加すればサインアップが表示されるようになったのですが、ちょっと不便です。 そこで、「About」「Home」画面のように、画面上部にリンクを作成してみましょう。

src/App.vue のHTML部分を以下のように書き換えます。

src/App.vue
<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link> |
      <router-link to="/auth">Signup</router-link>
    </div>
    <router-view/>
  </div>
</template>

新しく追加したのは <router-link> タグです。 ルーティング情報に追加したパスを to 属性に指定することで、そのページへ遷移してくれるリンクを作成してくれます。

3. アプリ実行

それでは、再度アプリをデプロイしてみます。

f:id:rennnosukesann:20181219212934g:plain

これでサインアップは成功です!

4. ユーザ情報の確認

登録したユーザ情報は、ダッシュボードの「Authentication」画面上で管理することができます。

f:id:rennnosukesann:20181219220727p:plain

ここでは登録したユーザ情報の編集や削除などができます。

5. ログイン画面の作成

サインアップ画面と同じように、次はログイン画面を作成していきましょう!

せっかくなので、先程の Auth.vue を使いまわします。 Auth クラスに、新たに以下のメソッドを追加します。

  private login() {
    firebase
      .auth()
      .signInWithEmailAndPassword(this.email, this.password)
      .then(() => {
        alert('Success to Log In!');
      })
      .catch((error) => {
        alert('Failed to Log In...\n error code : ' + error.code + ', error message : ' + error.message);
      });
  }

signInWithEmailAndPassword() メソッドはメールアドレス・パスワードによる認証を実行します。 使用方法は登録時と同じで、引数にメールアドレス・パスワードを渡して呼び出すだけです。 非同期処理の結果は then catch で受け取ります。

そしてHTML部分を以下のように編集します。

<template>
  <div class="auth">
    <p v-if="isLogin">Log In</p>
    <p v-else>Sign Up</p>
    <input v-model="email" placeholder="E-mail">
    <input type="password" v-model="password" placeholder="password">
    <span class="check"><input type="checkbox" v-model="isLogin"/><p>LogIn</p></span>
    <div class="button" v-if="isLogin" @click="login">Log In</div>
    <div class="button" v-else @click="signup">Sign Up</div>
  </div>
</template>

チェックボックスを用意し、Login用のフォームに切り替えられるようにしました。 (実際のアプリではもっとユーザーが混乱しないように作るべきですが)

v-if はVueのディレクティブで、渡した値の条件がtrueのときに要素を追加します。 v-else は対となる v-if 条件が成り立たないときに要素を追加します。

CSSも少し追加。

.auth .check {
  display: flex;
  align-items: center;
  width: 100px;
}

6. アプリ再起動

では、この状態でアプリを起動してみます。

f:id:rennnosukesann:20181219225232g:plain

無事ログインできました!


Firebaseの認証はWebアプリだけでなく、iOSAndroidなどのネイティブアプリにも使用可能です! ReactNativeですが過去記事にも掲載したので、参照していただけるとうれしいです!

rennnosukesann.hatenablog.com

参考文献

Add Firebase to your JavaScript Project  |  Firebase