六月 4, 2019 | 前端與Vue
[nuxt 教學]Firebase Google Login in Vuex
若開發小型專案,直觀選擇的資料庫一定會有Firebase,Firebase輕便、快速,結合Vuex實作登入系統以及後續資料處理相當流暢,本文針對實作登入系統先做介紹。
step.1 建立Firebase資料庫
先到Firebase官方網站建一個新的專案資料庫,建立完後點選該專案,應該會看到該畫面。
中間有三個白色icon,依序是ios、Android及Web,我們要建立Web版本所以選擇第三個,如下圖所示。
進來之後註冊一個新的應用程式
進入步驟二會出現以下畫面,若這裡資料錯誤,後續跟Firebase的互動一定會出問題。
step.2 在Nuxt建立Firebase資料夾
建立Firebase資料夾先安裝Firebase所需套件。
npm init
npm install --save firebase firebase-app js-cookie jwt-decode cookieparser
在Nuxt根目錄底下建立firebase/app.js
app.js裡要放入剛剛step.1取得的資料。
import firebase from 'firebase'
// uncomment the below if you use firestore DB instead of firebase DB
// require('firebase/firestore')
var firebaseConfig = {
apiKey: "你的apiKey",
authDomain: "fir-logindemo-9e00c.firebaseapp.com",
databaseURL: "https://fir-logindemo-9e00c.firebaseio.com",
projectId: "fir-logindemo-9e00c",
storageBucket: "fir-logindemo-9e00c.appspot.com",
messagingSenderId: "你的messagingSenderId",
appId: "你的appId"
};
const googleProvider = new firebase.auth.GoogleAuthProvider()
export default !firebase.apps.length ? firebase.initializeApp(firebaseConfig) : firebase.app()
export {googleProvider}
step.3 建立登入系統所需之相關檔案
根目錄建/helpers/app.js
import jwtDecode from 'jwt-decode'
var cookieparser = require('cookieparser')
export function getUserFromCookie (req) {
if (process.server && process.static) return
if (!req.headers.cookie) return
if (req.headers.cookie) {
const parsed = cookieparser.parse(req.headers.cookie)
const accessTokenCookie = parsed.access_token
if (!accessTokenCookie) return
const decodedToken = jwtDecode(accessTokenCookie)
if (!decodedToken) return
return decodedToken
}
}
export function getUserFromSession (req) {
console.log('[CHECK-AUTH] - checking if user is stored in session')
return req.session ? req.session.userId : null
}
middleware 新增 authenticated.js、check-auth.js、handle-login-route.js
/middleware/authenticated.js
export default function ({ store, redirect }) {
if (!store.getters['modules/user/isAuthenticated']) {
return redirect('/auth/signin')
}
}
/middleware/check-auth.js
import {getUserFromCookie, getUserFromSession} from '@/helpers'
export default function ({store, req}) {}
/middleware/handle-login-route.js
export default function ({ store, redirect }) {
if (store.getters['modules/user/isAuthenticated']) {
return redirect('/protected')
}
}
step.4 建立Vuex相關資料
在store底下建立index.js及modules/user.js
/store/index.js
import {getUserFromCookie, getUserFromSession} from '@/helpers'
export const actions = {
async nuxtServerInit ({ dispatch }, { req }) {
const user = getUserFromCookie(req)
if (user) {
await dispatch('modules/user/setUSER', { name: user.name, email: user.email, avatar: user.picture, uid: user.user_id})
}
}
}
/store/modules/user.js
import firebaseApp from '~/firebase/app'
import Cookies from 'js-cookie'
export const state = () => ({
uid: null,
user: null,
})
export const getters = {
uid(state) {
if (state.user && state.user.uid) return state.user.uid
else return null
},
user(state) {
return state.user
},
isAuthenticated(state) {
return !!state.user && !!state.user.uid
},
}
export const actions = {
async nuxtServerInit ({ dispatch }, { req }) {
const user = getUserFromCookie(req)
if (user) {
await dispatch('modules/user/setUSER', { name: user.name, email: user.email, avatar: user.picture, uid: user.user_id})
}
},
async login({dispatch, state}, user) {
// console.log('[STORE ACTIONS] - login')
const token = await firebaseApp.auth().currentUser.getIdToken(true)
const userInfo = {
name: user.displayName,
email: user.email,
avatar: user.photoURL,
uid: user.uid
}
if (user !== null) {
this.userName = user.displayName;
};
Cookies.set('access_token', token) // saving token in cookie for server rendering
await dispatch('setUSER', userInfo)
await dispatch('saveUID', userInfo.uid)
// console.log('[STORE ACTIONS] - in login, response:', status)
},
async logout({commit, dispatch}) {
// console.log('[STORE ACTIONS] - logout')
await firebaseApp.auth().signOut()
Cookies.remove('access_token');
commit('setUSER', null)
commit('saveUID', null)
},
saveUID({commit}, uid) {
// console.log('[STORE ACTIONS] - saveUID')
commit('saveUID', uid)
},
setUSER({commit}, user) {
commit('setUSER', user)
},
}
export const mutations = {
saveUID (state, uid) {
// console.log('[STORE MUTATIONS] - saveUID:', uid)
state.uid = uid
},
setUSER (state, user) {
// console.log('[STORE MUTATIONS] - setUSER:', user)
state.user = user
},
}
這樣一來初步的登入系統只差樣式及連接Vuex確認登入狀態的js就都完成了,趕緊來設定吧!
step.5 登入系統Template及Js
在pages建立以下路徑及檔案
路徑結構大致分為三個
1./pages/index.vue 主頁面 2./pages/auth/signin.vue 登入頁面 3./pages/protected/index.vue 登入後才能跳轉到該頁面
主頁面本次不在登入系統設計內,暫不討論,直接到/pages/auth/signin.vue開始設計登入系統跟Template及Js。
需要注意的是動作綁定,我們透過@click綁定Firebase google登入的方法
範例樣式如下:
section
.container
.loginitem.googleup
button(type="button" class="btn btn-Light" @click.prevent="fbGoogleLogin") Google登入
img(src="~/static/google_PNG19635.png" class="googleLogo")
加點css後範例畫面如下:
剛剛在樣式裡有寫到 @click.prevent="fbGoogleLogin
,緊接著寫登入方法吧!
import { mapActions } from 'vuex'
import firebaseApp, {googleProvider} from '~/firebase/app'
export default {
middleware: ['handle-login-route'],
methods: {
...mapActions('modules/user', [ 'login' ]),
async fbGoogleLogin() {
const { user } = await firebaseApp.auth().signInWithPopup(googleProvider)
await this.login(user)
this.$router.push('/protected')
}
}
}
完成後回到登入畫面按下按鈕,就會看到選擇google帳戶登入的驗證跳出來啦。
選擇完帳戶後驗證成功,畫面就會跳轉到this.$router.push('/protected')
的指定路徑。
結論
Firebase不管是登入驗證機制及資料庫的控管都相當容易,結合vuex可以確認當前用戶的登入狀態,方便做後續應用,在小型專案上若有帳戶登入及資料庫管理的需求,不妨實際來體驗Firebase的輕便快速吧。