vue


fibase 문서 참조

1) https://firebase.google.com/docs/auth/web/password-auth?hl=ko

2) https://firebase.google.com/docs/auth/web/google-signin?hl=ko

3) 백엔드 서버 nodejs functions 으로 회원 레벨 개발 처리

https://firebase.google.com/docs/auth/admin/custom-claims?hl=ko

 

* 회원가입 및 로그인 중요한 코드 내용은  다음 내용이다.

 
       
  // 구글 인증으로 가입시
        async signInWithGoogle() {
                const provider = this.$provider;
                const auth = this.$auth;
                auth.languageCode = 'ko';
                                
                //1.구글 인증 (인증과 동시에  firebase 의 Authentication 에 등록되어 있지않으면 등록처리된다.)
                //등록시 fireabse functions 커스텀등록을 통해 에 유저 level 설정 할수 있다.
                //참조 : https://firebase.google.com/docs/auth/admin/custom-claims?hl=ko
                // 백엔드 서버 노드js function 개발  : exports.processSignUp = functions.auth.user().onCreate(async (user)
                await this.$signInWithPopup(auth, provider);

                //2.현재 토큰 정보가져오기 - getIdTokenResult  true 를해야 토큰값이 갱신된다.
                const user= await auth.currentUser.getIdTokenResult(true);

                //3.firebase store 또는 DB에 유저정보 확인
                const confirmUser= await this.$fbGetData("members", user.claims.email);

                if(confirmUser.data()==undefined){ 
                    //confirmUser
                    //4. firebase store 또는 기타 mysql DB 등에 에 유저 정보 저장  - 아이디는 이메이로) 예 claims.email                     
                    await this.$fbWriteSetDoc("members", user.claims.email, user.claims);  
                    
                    //store.  인증처리 결과르 확인을 위한 vue 프론트의 임의 변수에 저장 처리
                    await this.$store.dispatch('setClaims', user.claims);
                } 


            
            //store에 레벨값이 들어올 때까지 기다린다.
            const accessLevel=await this.$store.state.claims.accessLevel;
            if(accessLevel){
                this.$router.push("/");
            }
     
        },


    //회원가입
           async memberJoin(){               
              console.log("memberJoin 2 ");
              if(!this.$refs.form.validate()) return  this.$toasted.global.error('입력폼을 올바르게 작성해 주세요.');                 
                                   
              const auth = this.$auth;
              auth.languageCode = 'ko';            
              
              //1. Authentication  에회원 이메일 비밀번호 최초등록 (기타 정보는 업데이트 처리 되지않는다.) 및 로그인 처리된다.
              //firebase functions 함수로 회원레벨 설정 함수가 등록되었을 시에 회원가입과 함께 회원레벨이 등록되어진다.
              await this.$createUserWithEmailAndPassword(auth, this.form.email, this.form.password);
              
              
              // 2. Authentication 에 이메일과 비밀번호 밖에 등록이 안되기 때문에 displayName 업데이트  및 photoURL 업데이트 처리한다.
               await this.$updateProfile(this.$auth.currentUser, {
                            displayName: this.form.lastName + this.form.firstName , photoURL: ""
               });


              //3.현재 토큰 정보가져오기 - getIdTokenResult  true 를해야 토큰값이 갱신된다.
              const user= await auth.currentUser.getIdTokenResult(true);

              //4.firebase store 또는  DB에 유저정보 확인
              const confirmUser= await this.$fbGetData("members", user.claims.email);

             if(confirmUser.data()==undefined){ 
                //5. firebase store 또는 기타 mysql DB 등에 에 유저 정보 저장  - 아이디는 이메이로) 예 claims.email                     
                await this.$fbWriteSetDoc("members", user.claims.email, user.claims);  
                
                //store.  인증처리 결과르 확인을 위한 vue 프론트의 임의 변수에 저장 처리
                await this.$store.dispatch('setClaims', user.claims);
            } 

            
            //store에 레벨값이 들어올 때까지 기다린다.
            const accessLevel=await this.$store.state.claims.accessLevel;
            if(accessLevel){
                this.$router.push("/");
            }    

          },


    //이메일과 비번으로 로그인시
    async signInEmail(email, password) {                                       
                    try {            
                        await this.$signInWithEmailAndPassword(this.$auth, email, password);                
                    } catch (error) {                
                        if(error.toString().indexOf('auth/wrong-password') !==-1){                            
                            this.$toasted.global.error("아이디 또는 비밀번호가 일치하지 않습니다.");                             
                        }else if(error.toString().indexOf('auth/user-not-found') !==-1){
                            this.$toasted.global.error("등록된 회원이 아닙니다.");   
                        }else{
                            this.$toasted.global.error(error.toString());   
                        }                        
                    }
                },


//로그아웃
                async signOut() {
                    await this.$signOut(this.$auth);             
                },

 

 

 

백엔드 서버 nodejs functions 

//등록 처리시
exports.createUser = functions.auth.user().onCreate(async (user) => {
  let customClaims = {
    admin: false,
    accessLevel: 1
  };

  if (user.email && user.email.endsWith('braverokmc79@gmail.com') && user.emailVerified) {   
     //관리자일경우
      customClaims = {
        admin: true,
        accessLevel: 9
      };      
  }

  await getAuth().setCustomUserClaims(user.uid, customClaims);

  
});

 

 

 

 

 

 

 

 

 

 

 

전체 

vuejs + firebase 처음 시작하기

 

 

https://firebase.google.com/docs/auth/web/password-auth?hl=ko&authuser=0

 

 

import { initializeApp } from "firebase/app";
import { signInWithPopup, GoogleAuthProvider, initializeAuth,
 browserSessionPersistence, browserPopupRedirectResolver } from "firebase/auth";

const firebaseConfig = {
   ...
};
const firebaseApp = initializeApp(firebaseConfig);

const auth = initializeAuth(firebaseApp, {
   persistence: browserSessionPersistence,
   popupRedirectResolver: browserPopupRedirectResolver,
});
const provider = new GoogleAuthProvider();
signInWithPopup(auth, provider)
   .then((result) => {
      ...
});

 

 

firebase.js

import "firebase/auth";
import "firebase/firestore";
import Vue from 'vue'
import * as firebase from 'firebase/app';
import { initializeApp } from 'firebase/app';
//import firebase 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 router from '../router'



//구글 로그인 인증
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();


//에뮬레이터 Firestore 사용시 다음 두줄 주석해제
//import { connectFirestoreEmulator } from "firebase/firestore";
//connectFirestoreEmulator(db, 'localhost', 8080);





//메시지 앱 푸시
//import { getMessaging } from "firebase/messaging";
//const messaging = getMessaging(app);






//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 : =>");
    console.log(user);
    
    store.dispatch('getUser', user)
    .then(r => {
        console.log("r : ");
        console.log(JSON.stringify(r));
        if (user) {
            Vue.prototype.$isFirebaseAuth = true;
            router.push("/");
        } else {
            //로그인 인증 안된경우
            Vue.prototype.$isFirebaseAuth = false;
            router.push("/sign");
        }       
     });    
});















//전역변수로 사용 설정
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



 

 

1 . auth/signIn.vue

<template>
  <v-card color="white" height="500">
      <v-form v-model="valid" ref="form" lazy-validation>
           
            <v-card-title primary-title text-md-center >
                <span class="title" ><h2 style="font-weight:bold" >로그인</h2></span>
                <v-spacer></v-spacer>
               
               
                <span class="caption white">                    
                <!-- <a  class="mr-1"  @click="$emit('type-change' , true)">로그인</a>  -->
                 또는 <a  class="mr-1"  @click="$emit('type-change', false)">회원가입</a></span>              
            </v-card-title>

            <v-card-actions justify-start>
                    <v-btn color="primary"
                        @click="$emit('signInWithGoogle')"
                      dark justify-start  block  class="pt-3 pb-3" 
                        style="height: 45px; text-transform: none" > 
                         <v-icon  >mdi-google</v-icon>
                             <v-divider vertical class="mx-3"></v-divider>
                        Google 계정으로 로그인
                    </v-btn>                
            </v-card-actions>
             <v-container grid-list-md fluid>
                <v-layout row wrap>
                    <v-flex xs5>                        
                       <v-divider class="mt-2"></v-divider>
                    </v-flex>
                    <v-flex xs2  text-md-center>
                        또는
                    </v-flex>
                    <v-flex xs5  >
                         <v-divider class="mt-2"></v-divider>
                    </v-flex>
                </v-layout>     
            </v-container>


            <v-card-text>
                <v-text-field label="이메일" v-model="email" 
                 :rules="[rule.required, rule.email]"                    
                ></v-text-field>
                <v-text-field label="비밀번호" v-model="password"   type="password"
                  :rules="[rule.required]"
                ></v-text-field>           
            </v-card-text>            
             <div class="px-3 recaptcha-terms-text" >이 페이지는 reCAPTCHA로 보호되며, Google 개인정보처리방침 및 서비스 약관의 적용을 받습니다.</div>
             <div class="px-3 recaptcha-terms-text"   style="color:red; font-weight:bold"  v-text="message"></div>    
            <v-card-actions>
                <v-checkbox label="로그인 정보저장" ></v-checkbox>
                <v-spacer></v-spacer>
                <v-btn v-if="!$store.state.user"
                 color="primary" @click="signInEmail" :disabled="!valid">로그인</v-btn>
                 <v-btn v-else  color="success" dark="dark" @click="$emit('signOut')">
                    <v-icon>mdi-logout</v-icon>
                    로그아웃
                 </v-btn>                
            </v-card-actions>

      </v-form>
  </v-card>
</template>

<script>

export default {
    props:{
       message:{
           type:String,
           required:false
       }
    },
    data(){
        return{
            valid:true,
            email:"",
            password:"",

            rule:{
                required:v => !!v || '필수 항목 입니다.',
                minLength:length => v => v.length >= length || `${length} 자리 이상 이여야 합니다.`,
                maxLength:length => v => v.length <= length || `${length} 자리 이하 이여야 합니다.`,
                email: v => /.+@.+/.test(v) || '이메일 형식에 맞지 않습니다.',
                passwordConfirm: v => v === this.form.password || `  패스워드가 일치하지 않습니다.`,
                agree:  v=> !!v || '약관에 동의해야 가입 가능합니다.'
            }
        }
    },

    computed:{
      
                  
       
    },

    methods:{
          signInEmail(){      
                console.log("이메일  값 : " + this.email);
                this.$emit('signInEmail', this.email, this.password);
          }
    }
}
</script>

<style scoped>
.recaptcha-terms-text{
    font-size: 14px;
    font-weight: 200;
    color: #637282;    
    font-family: 'Noto Sans KR', sans-serif;
    font-weight: 400;    
}
</style>

 

 

 

2. auth/signUp.vue

!<template>
  <v-card color="white" height="auto">
      
      <v-form v-model="valid" ref="form" lazy-validation>
           
            <v-card-title primary-title text-md-center >
                <span class="title" ><h2 style="font-weight:bold" >회원가입</h2></span>
                <v-spacer></v-spacer>
               
               
                <span class="caption white">                    
                <!-- <a  class="mr-1"  @click="$emit('type-change' , true)" >로그인</a>  -->
                 또는 <a  class="mr-1"  @click="$emit('type-change', true)">로그인</a></span>              
            </v-card-title>

             <v-container grid-list-md fluid>
                <v-layout row wrap>
                    <v-flex xs5>                        
                       <v-divider class="mt-2"></v-divider>
                    </v-flex>
                    <v-flex xs2  text-md-center>
                        또는
                    </v-flex>
                    <v-flex xs5  >
                         <v-divider class="mt-2"></v-divider>
                    </v-flex>
                </v-layout>     
            </v-container>

           <v-card-actions justify-start>
                    <v-btn color="primary"
                        @click="signInWithGoogle"
                      dark justify-start  block  class="pt-3 pb-3" 
                        style="height: 45px; text-transform: none" > 
                         <v-icon  >mdi-google</v-icon>
                             <v-divider vertical class="mx-3"></v-divider>
                        Google 계정으로 가입
                    </v-btn>                
            </v-card-actions>

            <v-card-text>

                <v-text-field label="성" v-model="form.lastName"  class="mb-3"
                :rules="[rule.required, rule.minLength(1), rule.maxLength(2)]"
                ></v-text-field>

                <v-text-field label="이름" v-model="form.firstName" class="mb-3"
                :rules="[rule.required, rule.minLength(1), rule.maxLength(10)]"
                ></v-text-field>
                
                <v-text-field label="이메일" v-model="form.email" 
                 :rules="[rule.required, rule.email ,rule.minLength(7), rule.maxLength(50)]"                    
                    class="mb-3"></v-text-field>
               
                <v-text-field label="비밀번호" v-model="form.password"   type="password" class="mb-3"
                :rules="[rule.required,rule.minLength(6), rule.maxLength(50)]"
                ></v-text-field>                   
               
                <v-text-field label="비밀번호확인" v-model="form.passwordConfirm" type="password" class="mb-3"
                 :rules="[rule.required, rule.passwordConfirm]"
                ></v-text-field>   


            </v-card-text>
             <div class="px-3 recaptcha-terms-text" >이 페이지는 reCAPTCHA로 보호되며,
                  Google 개인정보처리방침 및 서비스 약관의 적용을 받습니다.</div>
             <div class="px-3 recaptcha-terms-text"   style="color:red; font-weight:bold"  v-text="message"></div>    
            <v-card-actions>
                <v-checkbox label="약관에 동의함" :rules=[rule.agree]  required></v-checkbox>
                <v-spacer></v-spacer>
                <v-btn color="primary"  @click="memberJoin" :disabled="!valid">회원가입</v-btn>      
          
            </v-card-actions>

                     

      </v-form>
  </v-card>
</template>

<script>
import { sendEmailVerification } from "firebase/auth";
export default {
    props:{
      
    },
    data(){
        return{
            valid:true,
            agree:false,          
            message:"",
            form:{
                firstName:'',
                lastName:'',
                email: '',
                password: '',
                passwordConfirm:'',
            },

            rule:{
                required:v => !!v || '필수 항목 입니다.',
                minLength:length => v => v.length >= length || `${length} 자리 이상 이여야 합니다.`,
                maxLength:length => v => v.length <= length || `${length} 자리 이하 이여야 합니다.`,
                email: v => /.+@.+/.test(v) || '이메일 형식에 맞지 않습니다.',
                passwordConfirm: v => v === this.form.password || `  패스워드가 일치하지 않습니다.`,
                agree:  v=> !!v || '약관에 동의해야 가입 가능합니다.'
            }
        }
    },

    methods:{

        // 구글 인증
        async signInWithGoogle() {
                const provider = this.$provider;
                const auth = this.$auth;
                auth.languageCode = 'ko';
                                
                //1.구글 인증 (인증과 동시에  firebase 의 Authentication 에 등록되어 있지않으면 등록처리된다.)
                //등록시 fireabse functions 커스텀등록을 통해 에 유저 level 설정 할수 있다.
                //참조 : https://firebase.google.com/docs/auth/admin/custom-claims?hl=ko
                // 백엔드 서버 노드js function 개발  : exports.processSignUp = functions.auth.user().onCreate(async (user)
                await this.$signInWithPopup(auth, provider);

                //2.현재 토큰 정보가져오기 - getIdTokenResult  true 를해야 토큰값이 갱신된다.
                const user= await auth.currentUser.getIdTokenResult(true);

                //3.firebase store 또는 DB에 유저정보 확인
                const confirmUser= await this.$fbGetData("members", user.claims.email);

                if(confirmUser.data()==undefined){ 
                    //confirmUser
                    //4. firebase store 또는 기타 mysql DB 등에 에 유저 정보 저장  - 아이디는 이메이로) 예 claims.email                     
                    await this.$fbWriteSetDoc("members", user.claims.email, user.claims);  
                    
                    //store.  인증처리 결과르 확인을 위한 vue 프론트의 임의 변수에 저장 처리
                    await this.$store.dispatch('setClaims', user.claims);
                }   

            
            //store에 레벨값이 들어올 때까지 기다린다.
            const accessLevel=await this.$store.state.claims.accessLevel;
            if(accessLevel){
                this.$router.push("/");
            }   
        },



           async memberJoin(){               
              console.log("memberJoin 2 ");
              if(!this.$refs.form.validate()) return  this.$toasted.global.error('입력폼을 올바르게 작성해 주세요.');                 
                                   
              const auth = this.$auth;
              auth.languageCode = 'ko';            
              
              //1. Authentication  에회원 이메일 비밀번호 최초등록 (기타 정보는 업데이트 처리 되지않는다.) 및 로그인 처리된다.
              //firebase functions 함수로 회원레벨 설정 함수가 등록되었을 시에 회원가입과 함께 회원레벨이 등록되어진다.
              await this.$createUserWithEmailAndPassword(auth, this.form.email, this.form.password);
              
              
              // 2. Authentication 에 이메일과 비밀번호 밖에 등록이 안되기 때문에 displayName 업데이트  및 photoURL 업데이트 처리한다.
               await this.$updateProfile(this.$auth.currentUser, {
                            displayName: this.form.lastName + this.form.firstName , photoURL: ""
               });


              //3.현재 토큰 정보가져오기 - getIdTokenResult  true 를해야 토큰값이 갱신된다.
              const user= await auth.currentUser.getIdTokenResult(true);

              //4.firebase store 또는  DB에 유저정보 확인
              const confirmUser= await this.$fbGetData("members", user.claims.email);

             if(confirmUser.data()==undefined){ 
                //5. firebase store 또는 기타 mysql DB 등에 에 유저 정보 저장  - 아이디는 이메이로) 예 claims.email                     
                await this.$fbWriteSetDoc("members", user.claims.email, user.claims);  
                
                //store.  인증처리 결과르 확인을 위한 vue 프론트의 임의 변수에 저장 처리
                await this.$store.dispatch('setClaims', user.claims);
            } 

            //6. 사용자에게 확인 메일 보내기  - firebase 에서 자동으로 이메일 전달 되며 메일 확인 후 클릭하면
             //인증 처리 된다. ", "email_verified": false 가,"  true 변경 처리"
            await sendEmailVerification(auth.currentUser);


            //store에 레벨값이 들어올 때까지 기다린다.
            const accessLevel=await this.$store.state.claims.accessLevel;
            if(accessLevel){
                this.$router.push("/");
            }    

          }


    }
}
</script>

<style scoped>
.recaptcha-terms-text{
    font-size: 14px;
    font-weight: 200;
    color: #637282;    
    font-family: 'Noto Sans KR', sans-serif;
    font-weight: 400;    
}
</style>

 

 

 

 

 

3.sign.vue

<template>
    
  <v-container grid-list-md class="mt-5">
    <v-layout row wrap align-center justify-center class="mt-5">
        <v-flex xs12 sm5 offset-sm1 class="hidden-xs-only mr-5 mt-5">
            <v-img src="https://haatadmindashboard.azurewebsites.net/public/admin_css/assets/images/login-img.svg" ></v-img>            
        </v-flex>


         <v-flex xs12 sm5 class="mt-5" >
            <sign-in v-if="type" 
            @signInWithGoogle="signInWithGoogle" @signOut="signOut" @signInEmail="signInEmail"
                 :message="message" @type-change="typeChange"
            ></sign-in>

            <sign-up v-else @type-change="typeChange" ></sign-up>
         </v-flex>             
        
    </v-layout>     
</v-container>    
</template>

<script>
//import store from "../store/index.js";
import SignIn from '@/components/auth/signIn';
import SignUp from '@/components/auth/signUp';

    export default {
        components:{
            SignIn,
            SignUp
        },

        data() {
            return {
                email: '', 
                password: '', 
                message: '',
                type:true,
                parentData:{
                    email: '', 
                    password: '', 
                }
            }
        },

        methods: {

                // 구글 인증
                async signInWithGoogle() {
                        const provider = this.$provider;
                        const auth = this.$auth;
                        auth.languageCode = 'ko';
                                        
                        //1.구글 인증 (인증과 동시에  firebase 의 Authentication 에 등록되어 있지않으면 등록처리된다.)
                        //등록시 fireabse functions 커스텀등록을 통해 에 유저 level 설정 할수 있다.
                        //참조 : https://firebase.google.com/docs/auth/admin/custom-claims?hl=ko
                        // 백엔드 서버 노드js function 개발  : exports.processSignUp = functions.auth.user().onCreate(async (user)
                        await this.$signInWithPopup(auth, provider);

                        //2.현재 토큰 정보가져오기 - getIdTokenResult  true 를해야 토큰값이 갱신된다.
                        const user= await auth.currentUser.getIdTokenResult(true);

                        //3.firebase store 또는 DB에 유저정보 확인
                        const confirmUser= await this.$fbGetData("members", user.claims.email);

                        if(confirmUser.data()==undefined){ 
                            //confirmUser
                            //4. firebase store 또는 기타 mysql DB 등에 에 유저 정보 저장  - 아이디는 이메이로) 예 claims.email                     
                            await this.$fbWriteSetDoc("members", user.claims.email, user.claims);  
                            
                            //store.  인증처리 결과르 확인을 위한 vue 프론트의 임의 변수에 저장 처리
                            await this.$store.dispatch('setClaims', user.claims);
                        } 

            
                     //store에 레벨값이 들어올 때까지 기다린다.
                    const accessLevel=await this.$store.state.claims.accessLevel;
                    if(accessLevel){
                        this.$router.push("/");
                     }     
                },



                async signInEmail(email, password) {                                       
                    try {            
                        await this.$signInWithEmailAndPassword(this.$auth, email, password);                
                    } catch (error) {                
                        if(error.toString().indexOf('auth/wrong-password') !==-1){                            
                            this.$toasted.global.error("아이디 또는 비밀번호가 일치하지 않습니다.");                             
                        }else if(error.toString().indexOf('auth/user-not-found') !==-1){
                            this.$toasted.global.error("등록된 회원이 아닙니다.");   
                        }else{
                            this.$toasted.global.error(error.toString());   
                        }                        
                    }
                },



                async signOut() {
                    await this.$signOut(this.$auth);
                    //this.$router.go();                 
                    //this.$router.push("/");
                },

                typeChange(type){
                    console.log("type-change");
                    this.type=type;
                },

        }
    }
</script>


 

 

 

 

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)


//    const displayName = user.displayName;
// const email = user.email;
// const photoURL = user.photoURL;
// const emailVerified = user.emailVerified;
// const uid = user.uid;

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) {
     console.log(" 저장된 setClaims ");
    //  console.log(claims);
    //  console.log(" 종료 setClaims ");      
      state.claims = claims;
    },

    dimLayerOpen(state) {
      console.log(" dimLayerOpen");
      state.dimLayer = true;
    },
    dimLayerClose(state) {
      state.dimLayer = false;
    },

  },

  actions: {
     
    getUser({commit}, user) {
      commit('setUser', user);
      if (!user) return;
      
      return user.getIdToken()
      .then(token => {        
        //  console.log(" token");
         console.log(token);
        commit('setToken', token);  
        
        return user.getIdTokenResult();
      })
      .then(r => {  
        commit('setClaims', r.claims);        
        return r.claims;
        
      })
    },

    setClaims({ commit }, claims) {
      commit('setClaims', claims);
    },

    dimLayerOpen({ commit }) {
        commit('dimLayerOpen');
      },
     dimLayerClose({ commit }) {
       commit('dimLayerClose');
      },

  },
  modules: {
  }
})

 

 

 

소스 :  https://github.com/braverokmc79/vf

소스 :   https://github.com/braverokmc79/vf/commit/c01d4666b556c7c2198ef397a46ea8615ae0500c

 

 

 

 

 

 

vue

 

about author

PHRASE

Level 60  라이트

엎어놓고 닷 냥 금 , 내용을 헤아려 보지도 않고 함부로 판단함을 이르는 말.

댓글 ( 5)

댓글 남기기

작성