vue

 

 

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

 

 


 

 

about author

PHRASE

Level 60  라이트

부모를 사랑하는 사람은 남을 미워하지 않으며, 부모를 공경하는 사람은 남을 얕보지 않는다. -불경

댓글 ( 4)

댓글 남기기

작성