はじめに
今回はVueとVue RouterとFirebaseを用いてログイン認証後の必要ページを作ってみましょう!
前準備の部分が長くなるので、認証後の処理だけを見たい人はこ↓こ↑をクリック
環境
- Vue.js 2(CLI)
- Vue Router
- Firebase
- Yarn
下準備
まずは新しいプロジェクト作り
マニュアルで作りましたが、Router
が必要なのでインストールされてあれば他のをインストールしていても問題ありません。
この記事では、説明のために最小構成でプロジェクトを作成します。
次ですが、ここはhistory
モードを使うのでy
で。
この後も数回、環境の設定をどうするか聞かれますが、今回のRoutingには影響しないので好みの設定で大丈夫です。
無事に作成が完了したら、一度yarn serve
を行い、バニラ状態のページを確認しておきましょう!
Firebaseをインストール
次にFirebase CLIをインストールしましょう。
Firebase CLI 公式ドキュメント
npm
npmの場合ですと、公式ドキュメントにある通り、
グローバル
npm install -g firebase-tools
ローカル
npm install -D firebase-tools
yarn
yarnを使用している例は公式にはありませんが、いつもの方法でインストールすることは可能です。
グローバル
yarn global add firebase-tools
ローカル
yarn add firebase-tools
正しくインストールされてるか確認
最後に正しくインストールされてるか確認しましょう。
firebase -V
と入力して、バージョン表記が表示されれば正しくインストールされています!
(※2020年2月29日現在では、7.14.0
が最新)
Firebaseの設定をする
インストールが無事終えたら、次はインストールしたプロジェクトのFirebaseの設定をします。
Firebase init
このコマンドを打ち込みます。
すると、英語で「初期化を行う手続きを続行してもいいかー?」(意訳)の問が出現し、
その後に、Firebaseのどの機能を使用するか選択する問が現れます。
今回は認証だけをやりたいのですが、少なくとも1つは機能を選択しなければいけないため、Hosting
を選択しました。
次にFirebaseのどのプロジェクトを使用するか?を聞かれます。
1つ目の選択肢はすでにFirebase上に存在する既存プロジェクトを使用する
2つ目は新しくプロジェクトを作成する
となっています。
もしプロジェクトを作っていなかったら2を、既存のを使用するなら1を選択しましょう。
この後、選択した機能毎をどう設定するかの問が行われ、
その問に答えた後に、SPA(シングルページアプリケーション)として設定するかの問が行われます。
SPAを使用したいので、これにはy
と入力します。
Firebaseの初期化の操作が終わり、このように表示されたら無事完了です!
Firebase ConsoleからAPI情報を作成
先にAPI情報などを記載するfirebase.js
を作成しましょう。
src
フォルダ配下に作成します。
import firebase from "firebase";
import "firebase/auth";
const config = {
apiKey: /**/,
authDomain: /**/,
databaseURL: /**/,
projectId: /**/,
storageBucket: /**/,
messagingSenderId: /**/,
appId: /**/,
measurementId: /**/
};
firebase.initializeApp(config);
export default firebase;
config
の中の情報は、Firebase Consoleのプロジェクト設定から取得してきましょう。
firebase/auth
をImportすることで、Firebaseの認証機能を使えるようにImportしています。
これらは必ず行うようにしましょう。
これで下準備は完了です!
次から実際に作成していきましょう!
必要なコンポーネントを作ろう
ルーティングや認証を行う処理などを作る前に、先に必要なコンポーネントを作ります。
必要なコンポーネントは、
- 登録(sing up)
- ログイン(sing in)
- ログアウト(sing out)
- 認証専用ページ
の4つになるので、これらを作っていきましょう。
サイトトップは初期作成で作られたコンポーネントをそのまま使ってしまいましょう。
コンポーネントを作成
先程必要になる4つのコンポーネントを作っていきましょう。
- 登録(sing up)
- ログイン(sing in)
- ログアウト(sing out)
の3つはコンポーネントは、Firebaseとの通信が必要になるため、
先ほど作っておいたAPI情報を含め初期化しておいたfirebase.js
をImportしておきましょう。
そうしないと、Firebaseの機能を使うことができません。
登録(sing up)
<template>
<div>
<h1>SING UP</h1>
<div>
<h3>E-mail</h3>
<input type="text" placeholder="E-mail" v-model="email" />
</div>
<div>
<h3>Password</h3>
<input type="text" placeholder="Password" v-model="password" />
</div>
<button @click="createUserAccount">Sing UP!!</button>
</div>
</template>
<script>
import firebase from "../firebase.js";
export default {
name: "singup",
data() {
return {
email: "",
password: ""
};
}
};
</script>
ログイン(sing in)
<template>
<div>
<h1>SING IN</h1>
<div>
<h3>E-mail</h3>
<input type="text" placeholder="E-mail" v-model="email" />
</div>
<div>
<h3>Password</h3>
<input type="text" placeholder="Password" v-model="password" />
</div>
<button @click="userSingIn">Sing in Now!!</button>
</div>
</template>
<script>
import firebase from "../firebase.js";
export default {
name: "singin",
data() {
return {
email: "",
password: ""
};
}
};
</script>
ログアウト(sing out)
<template>
<div>
<h1>SING OUT</h1>
<button @click="singout">Sing out Now!!</button>
</div>
</template>
<script>
import firebase from "../firebase.js";
export default {
name: "singout"
};
</script>
認証専用ページ
<template>
<div>
<h1>SING OUT</h1>
<p>My Page!!<p>
</div>
</template>
<script>
export default {
name: "mypage"
};
</script>
ルーティング
次に作成したコンポーネントを合わせてルートレコードを設定していきましょう
ルートファイルを設定
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "../views/Home.vue";
/*ここから新規追加*/
import Singup from "../components/singup.vue";
import Singin from "../components/singin.vue";
import Singout from "../components/singout.vue";
import Mypage from "../components/mypage.vue";
/*ここまで*/
Vue.use(VueRouter);
const 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: "/singup",
name: "singup",
component: Singup
},
{
path: "/singin",
name: "singin",
component: Singin
},
{
path: "/singout",
name: "singout",
component: Singout
},
{
path: "/mypage",
name: "mypage",
component: Mypage
}
/*ここまで*/
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
export default router;
先程作成したコンポーネントをrouter.js
に追加し、ルーティング設定しました。
次に、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="/singup">Sing up</router-link> |
<router-link to="/singin">Sing in</router-link> |
<router-link to="/singout">Sing out</router-link> |
<router-link to="/mypage">Mypage</router-link> |
/*ここまで*/
</div>
<router-view />
</div>
</template>
ここまでのを確認
yarn serve
を行い、一旦ここまでの作成段階のを確認しましょう。
Sing upからMypageまでのリンクを押し、無事ページが遷移したら成功です。
Firebaseを使い認証
FirebaseでE-mailとPasswordで登録できるように設定しよう
認証などの処理を行う前に、Firebase Console画面で、Authenticationの設定を行いましょう。
Authenticationのログイン方法で、メール/パスワードを有効化します。
メールリンクは今回は有効化しなくてもOKです。
これでメール/パスワードを用いてユーザー登録を行う準備が完了しました。
Firebaseにアカウントを登録しよう
先程作ったSingup
コンポーネントに、ユーザーアカウントを追加する処理を組み込みましょう。
Firebaseのユーザーを管理する
<script>
methods: {
createUserAccount() {
firebase
.auth()
.createUserWithEmailAndPassword(this.email, this.password)
.then(() => {
alert("Create Account");
})
.catch(error => {
alert("Error!", error.message);
console.error("Account Regeister Error", error.message);
});
}
}
</script>
E-mail
とPassword
を用いてのよくあるユーザー登録を行うには、
firebase.auth
のcreateUserWithEmailAndPassword
メソッドを使用します。
第一引数にE-mail
、第二引数にPassword
を渡してあげると、あとはよしなにやってくれます。
非同期で行うため、結果はthenチェーン
内で行う必要があります。
あとは、このメソッドをButton
コンポーネントより呼び出せば登録処理部分は完了です。
ログイン処理をしよう
次はログインを行う処理を追加するために、作っておいたSing in
コンポーネントに処理を書き込んでいきましょう。
<script>
methods: {
userSingIn() {
firebase
.auth()
.signInWithEmailAndPassword(this.email, this.password)
.then(() => {
alert("ログイン成功!");
this.$router.push("/mypage");
});
}
}
</script>
firebase.auth
のsignInWithEmailAndPassword
メソッドを使い、ログイン処理を行います。
ユーザー登録時と同じ様に、引数にそろぞれE-mail
とPassword
を渡ししてあげればOKです。
無事ログイン処理が行えたら、then
チェーンで内でRouter
のpush
メソッドを使い、ページを遷移させています。
お試しにログインしてみる
先程作ったユーザ登録画面とログイン画面で、ユーザー登録を行えログインできるか試してみましょう。
ユーザ登録画面で登録が成功とalert
が表示され、Firebase Console
の認証関連のページで、ユーザーが登録されているはずです。
ログイン画面で、登録したE-mail
とPassword
でログインができ、画面がMypageに遷移したらログイン画面も無事作成できています。
ログアウト処理も作ってみる
ログインページが完了したので、次はログアウトページも作っておきましょう。
<script>
methods: {
singout() {
firebase
.auth()
.signOut()
.then(() => {
alert("Logout!");
})
.catch(error => {
alert(error);
});
}
}
</script>
firebase.auth
のsignOut
メソッドを使いログアウト処理を行っています。
ログアウト処理はこれだけで完了です。
ログアウト後にページトップに戻るような動きをつけたい場合には、
ログイン処理時に使った、
this.$router.push();
を使い、push
の引数の中に遷移させたい先のルート名を渡しましょう。
ページにログイン認証を組み込もう
ログイン/ログアウトできるようになりましたが、現状ではログイン時のみしか表示させたくないMypage
がログアウト時でも見ることができています。
次は、このMypage
をログイン時のみ表示するようにしましょう。
(ようやくここに来て本題に到達)
認証が必要なことの状態をもたせよう
まず、router.js
に認証処理を追加していきましょう。
{
path: "/mypage",
name: "mypage",
component: Mypage,
meta: { requiresAuth: true }
}
まずは、mypage
のルーティング部分にmeta
フィールドを追加します。
Vue Router - ルートメタフィールド
meta
フィールドに{ requiresAuth: true }
のオブジェクトをもたせて、このルートは認証が必要であることの状態をもたせます。
ただし、これだけでは状態を持っているだけなので、ナビゲーションガード、未ログインユーザーがこのページにアクセスしてもページが表示されてしまいます。
別途、ルートガードの処理を作る必要があります。
ナビゲーションガードを実装しよう
Vue Router - ナビゲーションガード
公式にある、router.beforeEach
を用いナビゲーションガードを実装してみましょう。
``
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
router.beforeEach((to, from, next) => {
const requiresAuth = to.matched.some(recode => recode.meta.requiresAuth);
if (requiresAuth) {
next({ path: "/singin", query: { redirect: to.fullPath } });
} else {
next();
}
});
export default router;
router.beforeEach
をexport default router
の前に追加しました。
to.matched.some(recode => recode.meta.requiresAuth)
で、requiresAuth
の状態をもつルートレコードなのかを確認しています。
もし、requiresAuth
ならnext
を用いてsingin
へ、そうでないならユーザーが選択したルートレコードへ遷移します。
ただし、この状態ですとログインしているかどうかを確認していないので、mypage
へアクセスすると誰でもログインページへ戻ってしまいます。
次は、Firebaseからログイン状態を取得してみましょう。
Firebaseからログイン状態を取得
router.beforeEach
の中にログイン状態を取得する方法もありますが、
今回はfirebase.js
に取得処理を書き、処理を分離化させる方法でやってみましょう。
firebase.js
の中に書いていきましょう。
firebase.getCurrentUser = () => {
return new Promise((resolve, reject) => {
const unsubscribe = firebase.auth().onAuthStateChanged(user => {
unsubscribe()
resolve(user);
}, reject);
});
};
Firebase のユーザーを管理する
onAuthStateChanged
を用い、ユーザーがログイン状態かを確認できます。
そして、このメソッドがログイン状態になったら即時にその情報を返します。
最後に先程のrouter.beforeEach
にこのログイン状態かを確認する処理を追加しましょう。
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
router.beforeEach(async (to, from, next) => {
const requiresAuth = to.matched.some(recode => recode.meta.requiresAuth);
if (requiresAuth && !(await firebase.getCurrentUser())) {
next({ path: "/singin", query: { redirect: to.fullPath } });
} else {
next();
}
});
export default router;
await firebase.getCurrentUser()
は先程firebase.js
に作成したメソッドとなります。
firebase.getCurrentUser()
はPromise
の非同期メソッドになるので、
router.beforeEach
内の関数にasync
をつけ、これも非同期メソッドとして上げる必要があります。
そして、if文の条件にfirebase.getCurrentUser()
を追加しますがこれは!
をつけ否定の条件にしておきます。
if (requiresAuth && !(await firebase.getCurrentUser())
そして、2つをand条件にすることで
- 認証が必要なコンポーネント
- ログイン状態でではない
を満たす場合のみに、ログインページへ遷移するようにしました。
最後に無事動作するか確認
最後に、yarn serve
を行い、ログインを行ってみてページ遷移するか、
ログアウト状態でMypageへアクセスした場合に、ログイン画面へ戻るかを確認してみましょう。
無事動けば完成です!
おわり
長くなりましたが、今回はFirebaseを用いてVueでのログイン認証が必要なページの作り方を記事にしてみました。
Vueの認証が必要なページの作り方は、Firebaseを使わなくてもrouter.beforeEach
の中で処理するのは共通になるので、一度覚えておけば他の認証サービスやAPIを使った場合でも応用は楽にできると思います。