Edited at

Vue.js の主要な機能をざっくりとつかってみたときのメモ(Firebase認証・認可編)

Vue.js の主要な機能をざっくりとつかってみたときのメモ」や「Vue.js の主要な機能をざっくりとつかってみたときのメモ(Firebase編)」のつづきです。。

前回までで、FirebaseのFirestoreにTodoリストをCRUDしました。今回はFirebaseのOAuthの認証・認可機能を使ってみます。

OAuthってのは、いわゆる「Googleアカウントでログイン」などのリンクを押すと、Googleのサイトのポップアップが出てきて、このアカウントをつかってログインしていい?って聞かれるヤツです。

image.png

本来は、認可サーバであるGoogleが「Firebaseをつかった(WEB)アプリに、あなたのGoogleアカウント情報を読ませてもいいかな?」って、Googleアカウントのオーナ(ユーザ)に許可つまり認可させるという「認可のための」仕組みなのですが、その際にポップアップでユーザを認証するため、結果として「Firebaseをつかった(WEB)アプリにGoogleアカウントでログインする(ユーザ情報が連携される)という処理シーケンスとなります。

参考:Authleteを使った認可サーバの構築と、OAuthクライアント(Webアプリケーション)からの疎通


そのまえに bootstrap-vue いれさせて

そのまえに、前回から、今回の記事作成までの最中にbootstrap-vue を導入しているので、そのインストールについて。


インストールとコードへの反映

$ npm install bootstrap-vue --save

インストールはこれだけであとは main.js に以下を追加します。


main.js

import BootstrapVue from "bootstrap-vue"

import "bootstrap/dist/css/bootstrap.min.css"
import "bootstrap-vue/dist/bootstrap-vue.css"
Vue.use(BootstrapVue)

これでvue.jsでbootstrap-vueが利用可能になりました。。Header.vueなどにログインリンクなどをつけたり適度に装飾してますが、コードはあとで出てくるので、ココでは割愛します :-)


Firebaseの認証をやってみる


Google認証を有効にする

Firebaseのコンソールから、自分が作成したプロジェクトを選択し、左のメニュー部の「Authentication」を選択。

image.png

「ログイン方法」を選択すると、下記のようにログイン方法を選択する画面になります。今回はGoogleをつかうので、プロバイダのGoogleを「有効」にしておきましょう。

image.png

OAuthの認可サーバを使用するときって、認可サーバ側からWEBアプリに対して「client_id/client_secret」を払い出してもらい、それらをパラメタに載せることでWEBアプリ自体の認証を行うのですが、Google もFirebaseもGoogle だからですかね、この辺はあらかじめ設定済みになってるようです。


承認済みドメインを追加する

この認証機能を利用出来るドメインを指定します。いまはlocalhostで起動しているので設定不要ですが、外部に公開するサーバのURLが http://client.example.com:8080 などだった場合、 client.example.com を設定追加しておきましょう。

image.png


ライブラリのインストール

Firebaseのライブラリは前回インストール済みなのですが、ログインしているユーザ情報やログイン状態をjsやvue間で共有するために、オブジェクトの状態を管理するフレームワークVuexを導入します。

Vuexは、 Vuex.Store というオブジェクトに対して、


store.js

import Vue from 'vue'

import Vuex from 'vuex'
import createPersistedState from 'vuex-persistedstate'

Vue.use(Vuex)

export default new Vuex.Store({
state: {
user: {},
loginStatus: false
},
mutations: {
user (state, user) { state.user = user },
loginStatus (state, loginStatus) { state.loginStatus = loginStatus }
},
plugins: [
createPersistedState({storage: window.sessionStorage, key: 'vuex-todo-examples'})
]
})


というインスタンスを保持する領域 user,loginStatusを作成しておき、jsやvueからは


Header.vue(のscript部)

<script>

import firebase from 'firebase'
export default {
name: 'Header',
computed: {
loginStatus () {
return this.$store.state.loginStatus // vuexのインスタンスを参照
},
user () {
return this.$store.state.user // vuexのインスタンスを参照
}
},
...
}
</script>

とやることで参照ができます。

保存しているインスタンスの更新については、直接プロパティを操作するのではなく


Login.vue(のscript部。あとで出てますが新規で作ったログイン画面)

<script>

import firebase from 'firebase'
export default {
name: 'Login',
... 割愛
methods: {
loginWithGoogle () {
const provider = new firebase.auth.GoogleAuthProvider()
firebase
.auth()
.signInWithPopup(provider)
.then(result => {
this.$store.commit('user', result.user) // インスタンスの更新
this.$store.commit('loginStatus', true) // インスタンスの更新
this.$router.push(
this.$route.query.redirect ? this.$route.query.redirect : '/'
)
})
.catch(function (error) {
const errorCode = error.code
const errorMessage = error.message
alert(errorMessage)
})
}
}
}
</script>

このように$store.commit('メソッド名','値') という仕様でVuex.Store にmutationsで定義していたメソッドを呼びだすことで、データを更新します。

このVuexをつかえばアプリケーション全体で状態が管理出来るので、Googleログインが成功した際やユーザ情報が更新されたとき、そのインスタンスを保存しておき、各画面ではそのインスタンスのあるなしで、ログイン済みかどうかを判定することができそうです。


ということでVuexのインストール

npm install --save vuex vuex-persistedstate

vuexはライブラリそのもの、vuex-persistedstate がそのデータをLocalStorageやSessionStorageに保存するためのライブラリです。


ソース追加・修正内容

さてソースについて。多いので一覧をつけました。

順番に見ていきましょう。


src/main.js で、Firebaseのユーザ情報の更新を検知

ユーザがログイン中かの判定は、Googleアカウントログイン後や、そのユーザ情報が更新された際、そのユーザ情報をvuexに保存しておいて、そのあるなしをチェックすればよいという話でした。

なのでmain.jsで先ほどのstore.jsをimportし「Firebaseの認証機能を経由してユーザ情報が更新されたときに呼ばれるコールバック」で、vuexのユーザ情報とログイン状態を更新することにしました。


src/main.js

// The Vue build version to load with the `import` command

// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import store from '@/store' // 追加
import firebase from 'firebase'
import firebaseConfig from '@/firebaseConfig'
import BootstrapVue from 'bootstrap-vue'
import 'bootstrap/dist/css/bootstrap.min.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
Vue.use(BootstrapVue)
firebase.initializeApp(firebaseConfig)
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.SESSION) // 追加
Vue.config.productionTip = false
// 追加
firebase.auth().onAuthStateChanged(function (user) {
// ユーザ情報が変更されたら呼ばれる
if (user) {
// User is signed in.
store.commit('user', user)
store.commit('loginStatus', true)
} else {
store.commit('user', {})
store.commit('loginStatus', false)
}
})
// ここまで
// router.beforeEach((to, from, next) => {
// あとで追加する
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})



src/store.js: Vuexの追加

ユーザ情報とログイン状態を保持するためのvuexを作成しました。先のソースとおなじものです。


src/store.js(新規)

// さっき載せたのとおなじ

import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from 'vuex-persistedstate'

Vue.use(Vuex)

export default new Vuex.Store({
state: {
user: {},
loginStatus: false
},
mutations: {
user (state, user) { state.user = user },
loginStatus (state, loginStatus) { state.loginStatus = loginStatus }
},
plugins: [
createPersistedState({storage: window.sessionStorage, key: 'vuex-todo-examples'})
]
})



components/Header.vue: ヘッダにログアウトリンクを追加

つづいてHeader.vueです。共通ヘッダにしていた箇所に(まだログインも実装してないんですがorz)ログアウトのリンクを追加します。

<template> に色々書いてますが、bootstrapのGUIの記述がほとんどです。ログアウトリンクの表示可否をvuexのloginStatus で制御しています。

また、ログアウトリンクをクリックしたときに呼ばれる logout() メソッドも追加しています。こちらもfirebase.auth().signOut() を呼び出している程度で、とてもシンプルです。


components/Header.vue

<template>

<b-navbar toggleable="md" type="dark" variant="info">
<b-navbar-toggle target="nav_collapse"></b-navbar-toggle>
<b-navbar-brand href="#">ToDo管理</b-navbar-brand>
<b-collapse is-nav id="nav_collapse">
<!-- Right aligned nav items -->
<b-navbar-nav class="ml-auto" v-if="loginStatus">
<b-nav-item-dropdown right>
<!-- Using button-content slot -->
<template slot="button-content">
<em>
<span>{{user.displayName}}</span>
</em>
</template>
<b-dropdown-item @click="logout()">{{user.displayName}}さんを Signout</b-dropdown-item>
</b-nav-item-dropdown>
</b-navbar-nav>
</b-collapse>
</b-navbar>
</template>

<script>
import firebase from 'firebase'
export default {
name: 'Header',
computed: {
loginStatus () {
return this.$store.state.loginStatus
},
user () {
return this.$store.state.user
}
},
methods: {
logout () {
firebase.auth().signOut()
// のちに画面遷移処理を追加する。
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>



router/index.js にログイン画面のルーティング追加

Routerについては、/login でログイン画面を表示させるためのルーティングを追加しています。


router/index.js

import Vue from 'vue'

import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Login from '@/components/Login'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
// ↓追加
{
path: '/login',
component: Login
}
]
})



components/Login.vue: /loginで呼ばれる画面を追加

さて /login で呼び出される実際のログイン画面です。

http://localhost:8080/#/login で表示されるログイン画面となります。


components/Login.vue(新規)

<template>

<b-container>
<div class="form-signin">
<button type="button" class="google-button" @click="loginWithGoogle">
<span class="google-button__icon">
<svg viewBox="0 0 366 372" xmlns="http://www.w3.org/2000/svg"><path d="M125.9 10.2c40.2-13.9 85.3-13.6 125.3 1.1 22.2 8.2 42.5 21 59.9 37.1-5.8 6.3-12.1 12.2-18.1 18.3l-34.2 34.2c-11.3-10.8-25.1-19-40.1-23.6-17.6-5.3-36.6-6.1-54.6-2.2-21 4.5-40.5 15.5-55.6 30.9-12.2 12.3-21.4 27.5-27 43.9-20.3-15.8-40.6-31.5-61-47.3 21.5-43 60.1-76.9 105.4-92.4z" id="Shape" fill="#EA4335"/><path d="M20.6 102.4c20.3 15.8 40.6 31.5 61 47.3-8 23.3-8 49.2 0 72.4-20.3 15.8-40.6 31.6-60.9 47.3C1.9 232.7-3.8 189.6 4.4 149.2c3.3-16.2 8.7-32 16.2-46.8z" id="Shape" fill="#FBBC05"/><path d="M361.7 151.1c5.8 32.7 4.5 66.8-4.7 98.8-8.5 29.3-24.6 56.5-47.1 77.2l-59.1-45.9c19.5-13.1 33.3-34.3 37.2-57.5H186.6c.1-24.2.1-48.4.1-72.6h175z" id="Shape" fill="#4285F4"/><path d="M81.4 222.2c7.8 22.9 22.8 43.2 42.6 57.1 12.4 8.7 26.6 14.9 41.4 17.9 14.6 3 29.7 2.6 44.4.1 14.6-2.6 28.7-7.9 41-16.2l59.1 45.9c-21.3 19.7-48 33.1-76.2 39.6-31.2 7.1-64.2 7.3-95.2-1-24.6-6.5-47.7-18.2-67.6-34.1-20.9-16.6-38.3-38-50.4-62 20.3-15.7 40.6-31.5 60.9-47.3z" fill="#34A853"/></svg>
</span>
<span class="google-button__text">Sign in with Google</span>
</button>
</div>
</b-container>
</template>
<script>
import firebase from "firebase";
// import 'firebaseui/dist/firebaseui.css'
export default {
name: "Login",
methods: {
loginWithGoogle() {
const provider = new firebase.auth.GoogleAuthProvider();
firebase
.auth()
.signInWithPopup(provider)
.then(result => {
this.$store.commit("user", result.user);
this.$store.commit("loginStatus", true);
this.$router.push(
this.$route.query.redirect ? this.$route.query.redirect : "/"
);
})
.catch(function(error) {
const errorCode = error.code;
const errorMessage = error.message;
alert(errorMessage);
});
}
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
html,
body {
height: 100%;
}
body {
display: -ms-flexbox;
display: flex;
-ms-flex-align: center;
align-items: center;
padding-top: 40px;
padding-bottom: 40px;
background-color: #f5f5f5;
}
.form-signin {
width: 100%;
max-width: 330px;
padding: 15px;
margin: auto;
}
.form-signin .checkbox {
font-weight: 400;
}
.form-signin .form-control {
position: relative;
box-sizing: border-box;
height: auto;
padding: 10px;
font-size: 16px;
}
.form-signin .form-control:focus {
z-index: 2;
}
.form-signin input[type="email"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
/* Shared */
.loginBtn {
box-sizing: border-box;
position: relative;
/* width: 13em; - apply for fixed size */
margin: 0.2em;
padding: 0 15px 0 46px;
border: none;
text-align: left;
line-height: 34px;
white-space: nowrap;
border-radius: 0.2em;
font-size: 16px;
color: #fff;
cursor: pointer;
}
.loginBtn:before {
content: "";
box-sizing: border-box;
position: absolute;
top: 0;
left: 0;
width: 34px;
height: 100%;
}
.loginBtn:focus {
outline: none;
}
.loginBtn:active {
box-shadow: inset 0 0 0 32px rgba(0, 0, 0, 0.1);
}
.google-button {
height: 40px;
border-width: 0;
background: white;
color: #737373;
border-radius: 5px;
white-space: nowrap;
box-shadow: 1px 1px 0px 1px rgba(0, 0, 0, 0.05);
transition-property: background-color, box-shadow;
transition-duration: 150ms;
transition-timing-function: ease-in-out;
padding: 0;
box-shadow: 1px 4px 5px 1px rgba(0, 0, 0, 0.1);
}
.google-button:hover {
cursor: pointer;
}
.google-button:active {
box-shadow: 3px 6px 7px 3px rgba(0, 0, 0, 0.1);
transition-duration: 10ms;
}
.google-button__icon {
display: inline-block;
vertical-align: middle;
margin: 8px 0 8px 8px;
width: 18px;
height: 18px;
box-sizing: border-box;
}
.google-button__icon--plus {
width: 27px;
}
.google-button__text {
display: inline-block;
vertical-align: middle;
padding: 0 24px;
font-size: 14px;
font-weight: bold;
font-family: "Roboto", arial, sans-serif;
}
</style>

npm run dev して表示してみると、こんな感じ。

image.png

コードが長くてちょっとアレですが、<template><style><script> それぞれみてみましょう。

まずtemplate部とstyle部いわゆる画面は、Googleログインのリンクボタンを追加しているだけです。styleはまあ長いですがボタンに適用しているcssですね。

つぎにボタンのクリックで呼ばれるメソッド loginWithGoogle (script部)ですが、

methods: {

loginWithGoogle(){
const provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(provider).then(......)
...
}
}

まずココまででポップアップが表示され、そのWindowsにGoogleがログイン画面を表示してくれます。

image.png

ポープアップ画面でGoogleへのログインとユーザの認可オペが完了すると、ポップアップは自動で閉じられ、thenに記述した下記のコールバックが呼び出されます。


then内のコールバック

result => {

this.$store.commit('user', result.user)
this.$store.commit('loginStatus', true)
this.$router.push(
this.$route.query.redirect ? this.$route.query.redirect : '/'
// あとで詳細説明
)
}

このコールバック処理ではvuexにあるuser/loginStatusを


  • コールバックに渡ってくるユーザ情報(result.user)

  • ログインステータスをtrue

で更新し、'/' へ画面遷移します。 '/'はルーティングでいままでのToDo画面が定義されているので、結果としてGoogle認証が完了するとToDo画面が表示されることになります。

image.png

ちなみにToDo画面であるHelloWorld.vue については、全体を

<main v-if="$store.state.loginStatus" class="container">

で囲うことで、ログインステータスが trueのときのみコンテンツを表示するようにしています。


HelloWorld.vue(のtemplate部)

<template>

<main v-if="$store.state.loginStatus" class="container">
<h1>
My Todo Task
<span class="info">({{remainingTask.length}}/{{todos.length}})</span>
<span class="info" style="cursor:pointer" @click="checkAll()" v-if="!isAllChecked()">すべてチェック/はずす</span>
<span class="info" style="cursor:pointer" @click="unCheckAll()" v-if="isAllChecked()">すべてチェック/はずす</span>
<b-button size="sm" variant="secondary" @click="deleteEndTask">完了タスクの削除</b-button>
</h1>
<ul>
<li v-for="todo in todos" :key="todo.id">
<input type="checkbox" v-model="todo.isDone" @click="toggle(todo.id)">
<span v-bind:class="{done: todo.isDone}">{{todo.name}}</span>
<span @click="deleteTask(todo.id)" class="xButton">[x]</span>
</li>
</ul>
<form @submit.prevent="addTask">
<input type="text" v-model="newTask" placeholder="タスクを入力">
<b-button type="submit" variant="primary" style="margin:4px">追加</b-button>
</form>
</main>
</template>


いま時点のソース

ここまでのソースは

https://github.com/masatomix/todo-examples/tree/for_qiita_auth_001

へコミット済みです。

一応このタグから構築する手順を示しておきます。

$ git clone --branch for_qiita_auth_001 https://github.com/masatomix/todo-examples.git

$ cd todo-examples/
$ npm install

src/firebaseConfig.js を自分の設定に書き換え

$ npm run dev

これで、http://localhost:8080/#/login にブラウザでアクセスできるとおもいます。


いったん整理

さてここまでで、Googleアカウントでログインして、ToDoアプリケーションを使用するという基本的なところができあがりました。しかしながらまだ

などを対応したいので、つづけてやっていきます。


ヘッダ右上のドロップダウンの「ログアウト」を選んだら、ログイン画面に遷移させたい

ヘッダのログアウトを選択すると、logout()が呼ばれますが、


Header.vue(のscript部)

methods: {

logout () {
firebase.auth().signOut()
// のちに画面遷移処理を追加する。
}
}

にログアウト後のコールバックを追加します。


Header.vue(のscript部)

methods: {

logout () {
firebase.auth().signOut()
.then(() => {
this.$router.push('/')
window.location.reload() // 保持してた不要な情報を一度クリア(vuexはきえない)
})
.catch(function (error) {
const errorCode = error.code
const errorMessage = error.message
alert(errorMessage)
})
}
}

this.$router.push('/') だとログイン画面ではなくてToDo画面に行こうとするんですが、このあとの機能追加で 「ログイン済み状態じゃなかったらログイン画面に飛ばす」処理を入れるので、結果ログイン画面に遷移します。

ちなみに firebase.auth().signOut() のコールバックに入った時点でユーザ情報は変更され、その結果main.jsに追加した


src/main.js

  firebase.auth().onAuthStateChanged(function (user) {// ユーザ情報が変更されたら呼ばれる

if (user) {
// User is signed in.
store.commit('user', user)
store.commit('loginStatus', true)
} else {
store.commit('user', {})
store.commit('loginStatus', false)
}
})

がうごきだして、vuex上の user,loginStatusはそれぞれ{}falseで更新されます。


画面に応じて、ログインが必要・必要でない、を制御したい

さて、認証されていない場合はログイン画面に飛ばしたいのですが、ログイン画面が認証が必要だと無限ループするので、画面によってログインの必要可否を制御したいですね。

ということで、画面ごとの定義を router/index.js に追加します。


router/index.js

import Vue from 'vue'

import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Login from '@/components/Login'

Vue.use(Router)

export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/login',
component: Login,
meta: {
isPublic: true // このプロパティ追加
}
}
]
})


isPublicがtrueの場合は、認証状態をチェックしないで画面を表示します。デフォルトはfalseなので、ログイン画面以外は認証が必要という設定になりました。

この次の項の画面遷移の制御で、上記の定義を参照する機能を追加します。


画面にアクセスしたときに、ログイン済みでない場合はログイン画面を表示し、認証したら該当画面へ遷移する

さあもうすこしです。


src/main.js にナビゲーションガードを追加する

公式のナビゲーションガード に説明がありますが、ナビゲーションガード機構を使うことで、画面の遷移をフックして、状態をチェックするなどの処理を入れ込むことが出来ます。

こんな感じに、main.jsでナビゲーションガードを追加します。


src/main.js

router.beforeEach((to, from, next) => {

const currentUser = store.state.user
if (currentUser.uid) {
if (to.path === '/login') {
firebase.auth().signOut().then(() => next())
}
}
if (to.matched.some(record => record.meta.isPublic)) {
// alert('isPublic = true '+ to.path)
next()
} else {
// alert('isPublic = false '+ to.path)
if (currentUser.uid) {
next()
} else {
next({
path: '/login',
query: {
redirect: to.path
}
})
}
}
})

つまり、URLが変更されるときに変更前のURL情報(from)と変更後のそれ(to)が渡ってくるので、


  • vuex からユーザ情報が取れたときは、toがログイン画面(/login)へのアクセスだったら、いちどログアウトさせてユーザ情報をクリアしてから、ログイン画面へ遷移(next())させる

  • 遷移先(to)のURLについて、isPublicがtrueの場合は、そのまま遷移(next())させる

  • isPublicがfalseの場合は、


    • vuex からユーザ情報(store.state.user.uid)が取れたときはそのまま遷移(next())

    • vuex からユーザ情報(store.state.user.uid)が取れない場合は、ログイン画面へ遷移させる(※))



最後の処理(※)は

next({

path: '/login',
query: {
redirect: to.path
}
})

の処理のことです。

/login に遷移する際 redirect というクエリパラメタに to.pathという変数をセットしていますが、たとえば /ui001 に遷移しようとしてナビゲーションガードによってログイン画面に遷移させられたとき、遷移後のログイン画面(/login)のURLが

http://localhost:8080/#/login?redirect=%2Fui001

とクエリパラメタが後ろにつくようにしています。このように redirect にto.pathを渡しているのは、ログインが成功した際に本来行きたかった画面のURL(/ui001ですね) の情報が必要だからです。


Login.vue でのログイン成功後の遷移先

さて、渡されたredirectパラメタですが、Login.vue でログイン成功後の画面遷移 はこのようになっていました。


Login.vue(抜粋)

this.$router.push(

this.$route.query.redirect ? this.$route.query.redirect : '/'
)

コレはつまり、redirectパラメタがある場合はそこのURLへ遷移、パラメタがない場合は '/' へ遷移(デフォルト値) するってことですね。

以上で、認証が必要な画面に行こうとした場合、ナビゲーションガードによって認証されているかがチェックされ、必要に応じてログイン画面を出した後、本来行きたい画面に遷移する流れを実装することが出来ました。

うーん、疲れましたね。。。


Firestore へのデータアクセスを、認証されたユーザのみに制限したい

さあFirebaseでの認証ができたので、せっかくなのでFirestoreへのアクセスを、認証されたユーザのみに出来たらよりセキュアですね。

そのための制御はFirebase側の画面にあります。

https://console.firebase.google.com から自分のプロジェクトに移動し、Database >> ルール に遷移します

image.png

ココですが、ワタクシまえに権限エラーに対応するため、下記の通りだれでもOK!ってしていたんですが、


だれでもOKの設定

service cloud.firestore {

match /databases/{database}/documents {
match /{document=**} {
allow read, write;
// allow read, write: if request.auth.uid != null;
}
}
}

これを


認証されてるヒトだけOK

service cloud.firestore {

match /databases/{database}/documents {
match /{document=**} {
//allow read, write;
allow read, write: if request.auth.uid != null;
}
}
}

にして「公開」ボタンを押せばOKです。ほどなくして反映されるようで、認証状態でないFirestoreへのアクセスにはエラーが返るようになりました。


ナビゲーションガードなどを入れたソース

最終形のソースは

https://github.com/masatomix/todo-examples/tree/for_qiita_auth_002

へコミット済みです。

下記手順でビルドできます。

$ git clone --branch for_qiita_auth_002 https://github.com/masatomix/todo-examples.git

$ cd todo-examples/
$ npm install

src/firebaseConfig.js を自分の設定に書き換え

$ npm run dev

これで、http://localhost:8080/#/ にブラウザでアクセスできるとおもいます。

ログイン画面 '/login' とToDo画面 '/' の他に、'/ui001','/ui002'という画面を追加でコミットしています。/ui001だけ認証が必要な画面にしてあるので、

http://localhost:8080/#/ui001 などに直接アクセスしてみて、ログイン画面が表示され、ログインするとちゃんと行きたかった画面に遷移できること、などを確認してみてください。


まとめ

Firebase認証をつかえば、OAuthをつかったGoogle認証機能を簡単に実装することが出来ましたね。

ザックリまとめると、、ログイン状態はVuexで管理し、ログイン時やユーザ情報の変更に従ってVuexの情報を更新します。また、画面遷移時にログイン状態をチェックするナビゲーションガードを導入することで、必要な時だけログイン画面を挟むことができるようになりました。最後にFirestoreへのアクセスを、Firebaseログインしているユーザに制限することで、データを保護することも出来ました。

以上です。おつかれさまでした。


関連リンク