第1回と第3回の記事はこちらになります
- 第1回
Nuxt.js + Firebase + Netlifyでログイン認証+Push通知機能のあるPWAを作る(その1) - 環境構築(Nuxt、Firebase設定、Netlifyホスティング、自動デプロイ) - Qiita - 第3回
Nuxt.js + Firebase + Netlifyでログイン認証+push通知機能のあるPWAを作る(その3) - Push通知受け取り&Functionsを使ってRealtimeDatabaseにトークンを保存 - Qiita
この回ではログイン画面、ユーザ登録画面からFirebase Authenticateを使用してログイン機能、ユーザ登録機能を実装していきます。
UIフレームワークはBootstrap Vueを使用します。(プロジェクト作成時に設定済み)
Vuexの実装
ログインしたユーザ情報をVuexのStoreに保存するためにaction,mutation,stateをStoreに定義します。
(Vuexの説明については割愛)
Firebaseのログイン、ログアウト、ユーザ登録処理
まずはFirebaseのログイン、ログアウト、ユーザ登録の実装を行います。
それぞれをメソッドとして定義します。
store/user.js
import firebase from '@/plugins/firebase'
const firebaseLogin = (user) => {
return new Promise((resolve, reject) => {
firebase
.auth()
.signInWithEmailAndPassword(user.email, user.password)
.then((data) => {
const { displayName, email } = data.user
resolve({ displayName, email })
})
.catch((error) => {
reject(error)
})
})
}
const firebaseLogout = (user) => {
return new Promise((resolve, reject) => {
firebase
.auth()
.signOut()
.then(() => {
resolve()
})
.catch((error) => {
reject(error)
})
})
}
const firebaseCreateUser = (user) => {
return new Promise((resolve, reject) => {
firebase
.auth()
.createUserWithEmailAndPassword(user.email, user.password)
.then((data) => {
resolve(data)
})
.catch((error) => {
reject(error)
})
})
}
state
保存先としてuserDataを定義。
store/user.js
export const state = () => ({
userData: null
})
getter
stateを参照するgetterを定義。
stateにユーザ情報があるかの判定を行うisAuthenticatedとstateのユーザ情報を取得するgetUserDataを定義します。
store/user.js
export const getters = {
isAuthenticated(state) {
return !!state.userData
},
getUserData(state) {
return state.userData
}
}
mutation
mutationにはユーザデータをstateにセットする処理を定義。
store/user.js
export const mutations = {
setUser(state, payload) {
state.userData = payload
}
}
action
ログイン、ログアウト、ユーザ登録、ユーザ情報セットのactionの定義を行います。
ユーザ登録に関してはユーザ登録が完了したタイミングでログインも行うようにします。
store/user.js
export const actions = {
async login({ commit }, user) {
try {
const loginResult = await firebaseLogin(user)
commit('setUser', loginResult)
return
} catch (e) {
throw new Error(e)
}
},
async logout({ commit }) {
try {
await firebaseLogout()
return
} catch (e) {
throw new Error(e)
}
},
async createUser({ commit }, user) {
try {
const createLogin = await firebaseCreateUser(user)
const resultLogin = await firebaseLogin(user)
commit('setUser', null)
return resultLogin
} catch (e) {
throw new Error(e)
}
},
setUserData({ commit }, user) {
commit('setUser', user)
}
}
ログイン画面
画面デザイン
画面構成は以下のようにします
- 「LOGIN」のタイトル
- メールアドレス入力欄
- パスワード入力欄
- ログインボタン
- ユーザ登録画面遷移リンク
pages/login.vue
<template>
<div>
<b-container fluid>
<b-row class="text-center" align-v="center">
<b-col cols="1" md="5" />
<b-col cols="10" sm="10" md="2">
<h1 style="margin-top: 60px;">LOGIN</h1>
<b-form style="margin-top: 30px;" @submit="signIn">
<b-form-group label="Email address" label-for="input-1">
<b-form-input
id="input-1"
type="email"
required
placeholder="Enter email"
v-model="email"
></b-form-input>
</b-form-group>
<b-form-group label="Password" label-for="input-2">
<b-form-input
id="input-2"
type="password"
required
placeholder="Enter password"
v-model="password"
></b-form-input>
</b-form-group>
<b-form-group style="margin-top: 30px;">
<b-button block type="submit" variant="success">
Sign In
</b-button>
</b-form-group>
</b-form>
<nuxt-link to="/createAccount">create account</nuxt-link>
</b-col>
<b-col cols="1" />
</b-row>
</b-container>
</div>
</template>
<script>
export default {
data() {
return {
email: '',
password: ''
}
},
methods: {
signIn(event) {
event.preventDefault()
console.log('sign in.')
}
}
}
</script>
ログイン処理実装
VuexのアクションからFirebaseログイン→トップに遷移の実装を行います。
actionのhelperをインポート。
import { mapActions } from 'vuex'
methods内にaction helperを用いて使用アクションの定義を行います。
...mapActions('user', ['login'])
signInメソッド内にactoinのloginを叩いてログインを行い、正常に処理が通ればトップに遷移する処理を実装します。
signIn(event) {
event.preventDefault()
const user = {
email: this.email,
password: this.password
}
this.login(user)
.then(() => {
this.$router.push('/')
})
.catch((error) => {
alert(error)
})
}
ここまで実装できたらFirebaseコンソールのAuthenticationの画面を開き、ユーザの追加
というボタンがあるので選択し、メールアドレスとパスワードを入力しユーザを追加します。
追加したユーザのメールアドレスとパスワードを使って実装したログイン画面からログインが可能になっています。
ユーザ登録画面
画面デザイン
画面構成は以下のようにします
- 「Create Account」のタイトル
- メールアドレス入力欄
- パスワード入力欄
- パスワード確認入力欄
- サインアップボタン
pages/createAccount.vue
<template>
<div class="loginbackgroud">
<b-row class="text-center" align-v="center">
<b-col cols="1" md="4" />
<b-col cols="10" sm="10" md="4">
<h1 style="margin-top: 60px;">Create Account</h1>
</b-col>
</b-row>
<b-container fluid>
<b-row class="text-center" align-v="center">
<b-col cols="1" md="5" />
<b-col cols="10" sm="10" md="2">
<b-form style="margin-top: 30px;" @submit="signUp">
<b-form-group label="Email address" label-for="input-1">
<b-form-input
id="input-1"
type="email"
required
placeholder="Enter email"
v-model="email"
></b-form-input>
</b-form-group>
<b-form-group label="Password" label-for="input-2">
<b-form-input
id="input-2"
type="password"
required
placeholder="Enter password"
v-model="password"
></b-form-input>
</b-form-group>
<b-form-group label="ConfirmPassword" label-for="input-2">
<b-form-input
id="input-2"
type="password"
required
placeholder="Enter confirm password"
v-model="confirmPassword"
></b-form-input>
</b-form-group>
<b-form-group style="margin-top: 30px;">
<b-button block type="submit" variant="success">
Sign Up
</b-button>
</b-form-group>
</b-form>
</b-col>
<b-col cols="1" />
</b-row>
</b-container>
</div>
</template>
<script>
import firebase from 'firebase'
import { mapActions } from 'vuex'
export default {
data() {
return {
email: '',
password: '',
confirmPassword: ''
}
},
methods: {
signUp() {
event.preventDefault()
console.log('sign up.')
}
}
}
</script>
ユーザ登録処理実装
VuexのアクションからFirebaseユーザ登録→ログイン→トップに遷移の実装を行います。
actionのhelperをインポート。
import { mapActions } from 'vuex'
methods内にaction helperを用いて使用アクションの定義を行います。
...mapActions('user', ['createUser'])
signUpメソッド内にactoinのcreateUserを叩いてユーザ登録、ログインを行い、正常に処理が通ればトップに遷移する処理を実装します。
signUp(event) {
event.preventDefault()
if (this.password !== this.confirmPassword) {
alert('Not match confirm password.')
return
}
const user = {
email: this.email,
password: this.password
}
this.createUser(user)
.then(() => {
this.$router.push('/')
})
.catch((error) => {
alert(error)
})
}
ここで実際に画面からメールアドレス、パスワードを入力し、submitすると一連の処理が正常に処理され、トップに遷移します。
FirebaseコンソールのAuthenticationのユーザを開くと先ほど入力したユーザが登録されます。
middlewareでログイン認証
middleware 設定
Nuxt.jsのmiddlewareの機能を使ってログイン済みかそうでないかの判定を行います。
Nuxtのmiddlewareはページ(パス)が変わりレンダリングされる前に実行する処理を実装することができる機能です。
middleware
ディレクトリにauthenticated.js
を作成。
touch middleware/authenticated.js
nuxt.config.js
にmiddlewareの登録を行います。
export default {
router: {
middleware: 'authenticated'
}
}
ログイン認証の実装
ここからログイン認証済みかそうでないかの処理を実装します。
FirebaseのonAuthStateChangedを使うとログイン済みであればユーザの情報が返ってくるのでこれを使用。
処理としては
- ログインしていない場合はログインページ、ユーザ登録ページ以外のページには飛ばないようにする
- ログイン済みの場合でVuexのstoreにログイン情報がない場合はstateに保存する
- ログイン済みの場合でログインページ、ユーザ登録ページに遷移しないようにする
これらを満たす処理を実装します
import firebase from 'firebase'
const auth = async ({ store, route, redirect }) => {
const user = await new Promise((resolve, reject) => {
firebase.auth().onAuthStateChanged((user) => resolve(user))
})
if (!user && !(route.name === 'login' || route.name === 'createAccount')) {
redirect('/login')
}
if (user && !store.getters['user/isAuthenticated']) {
const { displayName, email } = user
store.dispatch('user/setUserData', { displayName, email })
}
if (user && (route.name === 'login' || route.name === 'createAccount')) {
redirect('/')
}
}
export default auth
これでログイン済みであればリロードしてもトップページに遷移してくれるようになりました。
まとめ
ログイン処理周りはFirebaseAuthentication使えばかなり簡単に実装ができます。
またNuxtのmiddlewareを使うことでログイン認証も簡単に実装できました。
Nuxtはmiddlewareの他にもルーティング簡単にできたりasyncDataメソッドとか便利な機能が多くていいですね。
次回はFirebase Cloud Messagingを使ってプッシュ通知の実装を行います。