firebase.js
Vue.prototype.$isFirebaseAuth = false; onAuthStateChanged(auth, (user) => { if (user) { Vue.prototype.$isFirebaseAuth = true; console.log("onAuthStateChanged ===>"); console.log(user); router.push("/"); } else { //로그인 인증 안된경우 Vue.prototype.$isFirebaseAuth = false; router.push("/sign") ; } store.dispatch('getUser', user); });
router/index.js
router.beforeEach((to, from, next) => { //인증후 true 일경우에만 이동 console.log("브라우터 네비게이션 가드 - beforeEach "); if (to.path != "/sign") { //로그인 페이지가 아닌 모든 경로 if (Vue.prototype.$isFirebaseAuth) next(); //인증이 된경우는 통과 return; } next(); })
소스 :https://github.com/braverokmc79/vf/commit/7a8a69e0bd7730c0c91dff27dfdae2b09e1c4b2c
로그인 : http://macaronics.net/index.php/m04/vue/view/1839
원리는
파이어베이스를 통해 로그인 후 파이어베이스에서 인증 정보 받아서 store 에 user, claims 저장 시킨다.
파이베이스 onAuthStateChanged( ) 함수는 실시간으로 를 통해 인증처리 정보를 감시하며 인증 처리되면 store 에 저장 시킨다.
네비게이션 가드 통해 페이지 이동전에 인증여부를 확인하고 레벨을 확인한다.
ex)
router/index.js
import Vue from 'vue' import VueRouter from 'vue-router' import Home from '../views/Home.vue' import store from '../store' Vue.use(VueRouter) const adminCheck = (to, form, next) => { console.log("adminCheck =>"); if (!store.state.user) { if (to.path !== '/sign') return next("/sign"); next("/test/lv2"); //게스트 페이지 } if (!store.state.user.emailVerified) return next("/userProfile"); if (store.state.claims.accessLevel <9) { throw Error("관리자만 들어갈 수 있습니다.") } next(); } const userCheck = (to, form, next) => { console.log("userCheck"); if (!store.state.user) { if (to.path !== '/sign') return next("/sign"); next("/test/lv2"); //게스트 페이지 이동 } if (!store.state.user.emailVerified) return next("/userProfile"); next(); } const guestCheck = (to, form, next) => { console.log("guestCheck"); return next(); } const routes = [ { path: '/', name: 'Home', component: Home } , { path: '/test/lv0', name: 'lv0', component: () => import('../views/test/lv0.vue'), beforeEnter: adminCheck } , { path: '/test/lv1', name: 'lv1', component: () => import('../views/test/lv1.vue'), beforeEnter: userCheck } , { path: '/test/lv2', name: 'lv2', component: () => import('../views/test/lv2.vue'), beforeEnter: guestCheck } , { path: '/sign', name: 'sing', component: () => import('../views/sign.vue'), beforeEnter: (to, from, next) => { console.log("값 :" +store.state.claims); if (store.state.user===null) return next(); next("/"); } } ] const router = new VueRouter( {mode: 'history', base: process.env.BASE_URL, routes} ) //stoer 에 파이어베이스 인증된 정보 값 user, clamis 값이 들어갈 때 까지 대기 구문 const waiteFirebase = () => { return new Promise((resolve, reject) => { let cnt = 0; const tmr = setInterval(() => { if (store.state.firebaseLoaded) { clearInterval(tmr) resolve(); } else if (cnt++ > 200) { //2초 clearInterval(tmr); reject(Error('파이어베이스 로드가 안되었습니다.')); } }) }, 10); } router.beforeEach((to, from, next) => { if (Vue.prototype.$isFirebaseAuth) next(); //인증이 된경우는 통과 waiteFirebase() .then(() => next()) .catch(e => Vue.prototype.$toasted.global.error(e.message)); }); const originalPush = VueRouter.prototype.push; VueRouter.prototype.push = function push(location) { return originalPush.call(this, location).catch(err => { if (err.name !== 'NavigationDuplicated') throw err; }); }; router.onError(e => { console.log("라우터 에러 : " + e.message); Vue.prototype.$toasted.global.error(e.message); }) export default router
plugins/firebase.js
import "firebase/auth"; import "firebase/firestore"; import Vue from 'vue' import * as firebase from 'firebase/app'; import { initializeApp } from 'firebase/app'; import { query, orderBy, startAfter, limit, endBefore, limitToLast } from "firebase/firestore"; import { getFirestore, collection, getDocs, serverTimestamp, addDoc, doc, getDoc, updateDoc, deleteDoc, setDoc } from 'firebase/firestore'; import firebaseConfig from '../../firebaseConfig.js'; import { head } from 'lodash' import store from "../store/index.js"; //구글 로그인 인증 import { signInWithPopup, GoogleAuthProvider, initializeAuth, browserSessionPersistence, browserPopupRedirectResolver, createUserWithEmailAndPassword, signInWithEmailAndPassword, onAuthStateChanged, signOut, updateProfile //getAuth } from "firebase/auth"; const app = initializeApp(firebaseConfig); const db = getFirestore(app); const auth = initializeAuth(app, { persistence: browserSessionPersistence, popupRedirectResolver: browserPopupRedirectResolver, }); const provider = new GoogleAuthProvider(); //collectionName => table 이름 //1. 아이디 자동 생성 firebase 저장하기 async function fbWrite(collectionName, objData) { //firebase 데이터 저장 - addDoc 일경우 아이디가 자동 생성 await addDoc(collection(getFirestore(), collectionName), objData); // 전체등록 갯수 가져오기 const docRef = doc(db, collectionName + "_totalCount", "tot_id"); const totNum = await getDoc(docRef); //전체등록 갯수 업데이트 // totNum.exists() 존재할 경우 업데이트 처리 - 카운트 증가처리 : 없으면 1 로 최초등록 await setDoc(doc(db, collectionName + "_totalCount", "tot_id"), { totalCount: totNum.exists() ? totNum.data().totalCount + 1 : 1, upDate: serverTimestamp() }); } //아이디가 존재할 경우 async function fbWriteSetDoc(collectionName, id, objData) { //firebase 데이터 저장 - setDoc 일경우 아이디가 자동 생성 await setDoc(doc(db, collectionName, id), objData); // 전체등록 갯수 가져오기 const docRef = doc(db, collectionName + "_totalCount", "tot_id"); const totNum = await getDoc(docRef); //전체등록 갯수 업데이트 // totNum.exists() 존재할 경우 업데이트 처리 - 카운트 증가처리 : 없으면 1 로 최초등록 await setDoc(doc(db, collectionName + "_totalCount", "tot_id"), { totalCount: totNum.exists() ? totNum.data().totalCount + 1 : 1, upDate: serverTimestamp() }); } //firebase 삭제하기 async function fbDelete(collectionName, id) { await deleteDoc(doc(db, collectionName, id)); // 전체등록 갯수 가져오기 const docRef = doc(db, collectionName + "_totalCount", "tot_id"); const totNum = await getDoc(docRef); //전체 갯수 업데이트 // totNum.docs[0] 값이 없을 경우 최초 등록으로 1 , 존재할 경우 업데이트 처리 - 카운트 감소 await setDoc(doc(db, collectionName + "_totalCount", "tot_id"), { totalCount: totNum.data().totalCount > 0 ? totNum.data().totalCount - 1 : 0, upDate: serverTimestamp() }); } //firebase 수정하기 async function fbUpdate(collectionName, objData) { const updateData = doc(db, collectionName, objData.id); await updateDoc(updateData, objData); } //firebase 한개의 데이터 가져오기 async function fbGetData(collectionName, id) { const docRef = doc(db, collectionName, id); return await getDoc(docRef); } // firebase 데이터 목록 가져오기 async function fbGetList(collectionName) { const querySnapshot = await getDocs(collection(db, collectionName)); return querySnapshot; } // firebase query 데이터 목록 가져오기 async function fbGetQueryList(collectionName, culum, order, pageSize, documentSnapshots, currentPage, beforPage) { //1. 첫 페이지일 경우 if (currentPage == undefined || currentPage == 1) { //1.첫페이지일 경우 const first = query(collection(db, collectionName), orderBy(culum, order), limit(pageSize)); const documentSnapshots2 = await getDocs(first); return documentSnapshots2; } if (beforPage <= currentPage) { //2.next 다음 페이지로 이동 const lastVisible = documentSnapshots.docs[documentSnapshots.docs.length - 1]; if (documentSnapshots.size == 0) { return; } const next = query(collection(db, collectionName), orderBy(culum, order), startAfter(lastVisible), limit(pageSize)); const documentSnapshots2 = await getDocs(next); return documentSnapshots2; } else { //3.이전 페이지로 이동 const prevVisible = documentSnapshots.docs; const before = query(collection(db, collectionName), orderBy(culum, order), endBefore(head(prevVisible)), limitToLast(pageSize + 1) ); const documentSnapshots2 = await getDocs(before); return documentSnapshots2; } } Vue.prototype.$isFirebaseAuth = false; // onAuthStateChanged(auth, (user) => { // if(user){ // Vue.prototype.$isFirebaseAuth = true; // router.push("/"); // } else { // Vue.prototype.$isFirebaseAuth = false; // router.push("/sign"); // } // store.dispatch('getUser', user) // }); onAuthStateChanged(auth, (user) => { console.log("onAuthStateChanged : =>"); store.dispatch('getUser', user); }); //전역변수로 사용 설정 Vue.prototype.$firebase = firebase Vue.prototype.$fbWrite = fbWrite Vue.prototype.$fbWriteSetDoc = fbWriteSetDoc Vue.prototype.$fbUpdate = fbUpdate Vue.prototype.$fbGetList = fbGetList Vue.prototype.$fbGetQueryList = fbGetQueryList Vue.prototype.$fbDelete = fbDelete Vue.prototype.$fbGetData = fbGetData Vue.prototype.$db = db Vue.prototype.$getFirestore = getFirestore Vue.prototype.$collection = collection Vue.prototype.$getDocs = getDocs Vue.prototype.$serverTimestamp = serverTimestamp Vue.prototype.$addDoc = addDoc Vue.prototype.$doc = doc Vue.prototype.$getDoc = getDoc Vue.prototype.$updateDoc = updateDoc Vue.prototype.$deleteDoc = deleteDoc Vue.prototype.$signOut = signOut Vue.prototype.$updateProfile = updateProfile Vue.prototype.$onAuthStateChanged = onAuthStateChanged Vue.prototype.$signInWithPopup = signInWithPopup Vue.prototype.$GoogleAuthProvider = GoogleAuthProvider Vue.prototype.$auth = auth Vue.prototype.$provider = provider Vue.prototype.$createUserWithEmailAndPassword = createUserWithEmailAndPassword Vue.prototype.$signInWithEmailAndPassword = signInWithEmailAndPassword
store/index.js
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { title: '원래 제목', user: null, token: '', loading: false, claims: null, firebaseLoaded: false, dimLayer: true }, mutations: { setTitle(state, payload) { state.title = payload; }, setUser(state, payload) { state.firebaseLoaded = true; state.user = payload; }, setToken(state, token) { state.token = token; }, setClaims(state, claims) { state.claims = claims; }, }, actions: { async getUser({commit}, user){ commit('setUser', user); if (!user) return; const token = await user.getIdToken(); commit('setToken', token); const resultToken = await user.getIdTokenResult(); commit('setClaims', resultToken.claims); }, setClaims({commit}, claims) { commit('setClaims', claims); }, }, modules: {} })
https://github.com/braverokmc79/vf/commit/4a44c612e88b53c4fc6a30a921f01de72b07033f
https://youtu.be/bxwhJKyYNnI?list=PLjpTKic1SLZs3GsJXwKgoJWu6wNQKt_GY
댓글 ( 4)
댓글 남기기