六月 4, 2019 | 前端與Vue

[nuxt 教學]Firebase Google Login in Vuex

[nuxt 教學]Firebase Google Login in Vuex 若開發小型專案,直觀選擇的資料庫一定會有Firebase,Firebase輕便、快速,結合Vuex實作登入系統以及後續資料處理相當流暢,本文針對實作登入系統先做介紹。 step.1 建立Firebase資料庫 先到Firebase官方網站建一個新的專案資料庫,建立完後點選該專案,應該會看到該畫面。 中間有三個白色icon,依序是ios、Android及Web,我們要建立Web版本所以選擇第三個,如下圖所示。 進來之後註冊一個新的應用程式
[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的輕便快速吧。