1. 로그인
이메일 패스워드를 입력하고 로그인 버튼은 누르면 signInWithEmailAndPassword로 구글에 로그인한 후 uid를 받아 이것으로 mylog의 사용자 정보를 가져와 로그인 설정을 합니다.
1.1 login
async login({ commit, dispatch }, { email, password }) {
try {
const { user } = await signInWithEmailAndPassword(auth, email, password);
//console.log('user::::', user);
// 웹앱의 계정 정보를 가져와 로그인 설정을 한다.
dispatch('fetchUserWithUid', {uid: user.uid});
router.push("/"); // home으로
} catch (error) {
commit('setError', error.message);
alert("Failed to log in: " + error.message);
}
},
1.2 fetchUserWithUid
async fetchUserWithUid({ commit }, {uid}) {
try {
const users = [];
const userRef = query(users_collection, where('uids', 'array-contains', uid));
const querySnapshot = await getDocs(userRef);
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
users.push({ id: doc.id, ...doc.data() });
});
// 로그인 설정을 한다.
commit('setUser', users[0]);
} catch (error) {
console.error('Error fetching user:', error);
}
},
2. 구글 계정 연결
구글 계정 연결은 사용자의 구글 계정의 uid를 mylog 계정에 저장합니다. 구글 로그인을 하게 되면 구글의 uid로 mylog의 계정을 가져와서 로그인 설정을 합니다.
2.1 addGoogleAccount
async addGoogleAccount({ commit, dispatch, getters }) {
try {
const provider = new GoogleAuthProvider();
const { user } = await signInWithPopup(auth, provider);
try {
// 이미 연동된 회원의 경우 알림 메시지 출력한다.
const myUser = getters.getUserByUid(user.uid);
if (myUser) {
// 이미 연동되어 있다.
commit('setError','이미 연동되어 있습니다.');
} else {
// 구글 연동을 진행한다.
dispatch('addUidToUser', user.uid);
}
} catch (error) {
commit('setError','Error adding google uid');
}
} catch (error) {
commit('setError', error.message);
}
},
2.2 getUserByUid
getUserByUid: (state) => (uid) => {
return state.users.find(user => user.uids && user.uids.includes(uid));
}
2.3 addUidToUser
async addUidToUser({ state }, newUid) {
//console.log('user.id:', state.user.id);
if (state.user) {
try {
const userDoc = doc(db, "users", state.user.id);
updateDoc(userDoc, {
uids: arrayUnion(newUid)
});
// Update the local state if neededa
state.user.uids = [...(state.user.uids || []), newUid];
} catch (error) {
console.error('Error adding UID to user:', error);
}
}
},
3. 구글 로그인
googleLogin
async googleLogin({ commit, getters }) {
try {
// 구글 계정에 로그인
const provider = new GoogleAuthProvider();
const { user } = await signInWithPopup(auth, provider)
//const { user } = await signInWithPopup(auth); //, googleProvider);
try {
// 구글계정의 uid로 웹앱 계정의 정보를 가져옴.
// 웹앱 계정은 사이트에 접속할 때 전체 회원 정보를 로드하였으므로
// 이미 로드된 회원 리스트에서 구글 계정 uid를 가진 myUser를 가져온다.
const myUser = getters.getUserByUid(user.uid);
if (myUser) {
//console.log('myUser: ', myUser);
commit('setUser', myUser);
router.push("/"); // home으로
} else {
console.log('등록된 회원이 아닙니다.');
commit('setError', '등록된 회원이 아닙니다.');
// 이경우 회원 가입 페이지로 이동 필요
}
} catch (error) {
//console.error('Error adding user:', error);
commit('setError', error.message);
}
} catch (error) {
commit('setError', error.message);
}
},
4. 자동 로그인
initializeAuth({ commit, dispatch }) {
onAuthStateChanged(auth, (user) => {
if (user) {
// user.uid로 웹앱의 firestore DB에서 계정 정보를 가져온다.
dispatch('fetchUserWithUid', {uid: user.uid});
// fetchUserWithUid에서 setUser를 실행한다.
// commit("setUser", user);
//dispatch("fetchUserInfo");
} else {
commit("setUser", null);
commit("setUserInfo", null);
}
});
},
5. 로그 아웃
async logout({ commit }) {
await auth.signOut();
commit('setUser', null);
router.push("/"); // home으로
},
6. Source Code
6.1 src/views/LoginView.vue
<!-- src/views/LoginView.vue -->
<template>
<v-container>
<v-row>
<v-col cols="12" class="text-center my-5">
<h3>로그인</h3>
</v-col>
</v-row>
<v-row>
<v-col class="text-center" cols="10" offset="1" sm="8" offset-sm="2">
<v-form @submit.prevent="loginUser">
<v-text-field v-model="email" label="이메일" type="email" required></v-text-field>
<v-text-field v-model="password" label="비밀번호" type="password" required></v-text-field>
<v-btn type="submit" color="primary">Login</v-btn>
<v-alert v-if="error" type="error" dismissible>{{ error }}</v-alert>
</v-form>
</v-col>
</v-row>
<v-row>
<v-col class="text-center" cols="10" offset="1" sm="8" offset-sm="2">
<v-btn color="red" @click="googleLogin" dark>
<v-icon left>mdi-google</v-icon>
Sign in with Google
</v-btn>
</v-col>
</v-row>
</v-container>
</template>
<script>
import { mapActions, mapGetters } from 'vuex';
export default {
name: 'Login',
data() {
return {
email: '',
password: ''
};
},
computed: {
...mapGetters('auth',['error'])
},
methods: {
...mapActions('auth', ['login', 'googleLogin']),
async loginUser() {
await this.login({ email: this.email, password: this.password });
}
}
};
</script>
6.2 src/views/ProfileView.vue
<!-- src/views/ProfileView.vue -->
<template>
<v-container>
<v-card v-if="user">
<v-card-title>User Profile</v-card-title>
<v-card-text>
<p><strong>이메일:</strong> {{ user.email }}</p>
<p><strong>이름:</strong> {{ user.name }}</p>
<p><strong>id:</strong> {{ user.id }}</p>
</v-card-text>
<v-card-text>
<v-btn color="red" @click="addGoogleAccount" dark>
<v-icon left>mdi-google</v-icon>
Google 계정 연동
</v-btn>
<v-alert v-if="error" type="error" dismissible @input="resetErrorMsg" class="my-alert">{{ error }}</v-alert>
</v-card-text>
</v-card>
<v-alert v-else type="info">No user is logged in.</v-alert>
</v-container>
</template>
<script>
import { mapActions, mapGetters } from 'vuex';
export default {
computed: {
...mapGetters('auth',['user', 'error'])
},
methods: {
...mapActions('auth',['addGoogleUid', 'resetError']),
async addGoogleAccount() {
await this.addGoogleUid();
},
resetErrorMsg() {
this.resetError();
}
}
};
</script>
<style scoped>
.my-alert {
margin: 20px 0;
}
</style>
6.3 src/firebase.js
// src/firebase.js
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
import { getFirestore, collection, addDoc, getDocs, query, where, updateDoc, doc, arrayUnion } from "firebase/firestore";
const firebaseConfig = {
apiKey: process.env.VUE_APP_FIREBASE_API_KEY,
authDomain: process.env.VUE_APP_FIREBASE_AUTH_DOMAIN,
projectId: process.env.VUE_APP_FIREBASE_PROJECT_ID,
storageBucket: process.env.VUE_APP_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.VUE_APP_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.VUE_APP_FIREBASE_APP_ID,
};
// npm install dotenv - env가 정상 동작하지 않을 때 설치 필요함
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore(app);
export { auth, db, collection, addDoc, getDocs, query, where, updateDoc, doc, arrayUnion };
6.4 src/main.js
// src/main.js
import Vue from 'vue'
import App from './App.vue'
import './registerServiceWorker'
import router from './router'
import store from './store'
import vuetify from './plugins/vuetify'
Vue.config.productionTip = false
new Vue({
router,
store,
vuetify,
render: h => h(App),
created() {
// Set up Firebase auth state change listener
const { dispatch } = this.$store;
// Initialize Firebase authentication to check for the logged-in user
dispatch('auth/initializeAuth');
dispatch('auth/fetchUsers');
}
}).$mount('#app')
6.5 src/store/modules/auth.js
Copy// src/store/modules/auth.js
import router from '@/router'; // Vue Router import
import { auth, db, collection, getDocs, query, where, updateDoc, doc, arrayUnion } from "@/firebase";
import { createUserWithEmailAndPassword, onAuthStateChanged, signInWithEmailAndPassword, GoogleAuthProvider, signInWithPopup } from "firebase/auth";
const state = {
user: null,
userInfo: null,
users: [],
isLoading: false,
error: null
};
const mutations = {
setUser(state, user) {
state.user = user;
},
setUserInfo(state, userInfo) {
state.userInfo = userInfo;
},
setUsers(state, users) {
state.users = users;
state.isLoading = false;
},
setError(state, error) {
state.error = error;
state.isLoading = false;
},
setLoading(state, isLoading) {
state.isLoading = isLoading;
}
};
const actions = {
async fetchUsers({ commit }) {
commit('setLoading', true);
try {
const users = [];
const userRef = collection(db, "users");
const querySnapshot = await getDocs(userRef);
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
users.push({ id: doc.id, ...doc.data() });
});
commit('setUsers', users);
} catch (error) {
commit('setError', error.message);
}
},
async addUser({ dispatch, commit }, user) {
try {
// Save additional user data to Firestore
const userRef = collection(db, "users");
const newUser = await addDoc(userRef, {
email: user.email,
uids: user.uids,
username: user.username,
mylogname: user.mylogname
});
// 로그인 설정
user.id = newUser.id;
commit('setUser', user);
dispatch('fetchUsers');
commit("setError", null);
} catch (error) {
console.error('Error adding user:', error);
}
},
async register({ commit, dispatch }, { email, password, username, mylogname }) {
try {
const userCredential = await createUserWithEmailAndPassword(auth, email, password);
const user = userCredential.user;
const newUser = {
email: email,
uids: [user.uid],
username: username,
mylogname: mylogname
};
//console.log('newuser:', newUser);
dispatch('addUser', newUser);
router.push("/"); // home으로
} catch (error) {
commit("setError", error.message);
}
},
async fetchUserInfo({ commit, state }, user) {
// if (!state.user) return;
// try {
// const q = query(collection(db, "users"), where("uid", "==", state.user.uid));
// const querySnapshot = await getDocs(q);
// querySnapshot.forEach((doc) => {
// commit("setUserInfo", { ...doc.data(), id: doc.id });
// });
// } catch (error) {
// commit("setError", error.message);
// }
try {
commit("setUserInfo", user);
} catch (error) {
commit("setError", error.message);
}
},
async updateUserInfo({ commit }, updatedInfo) {
try {
const userDoc = doc(db, "users", updatedInfo.id);
await updateDoc(userDoc, updatedInfo);
commit("setUserInfo", updatedInfo);
commit("setUser", updatedInfo);
commit("setError", null);
} catch (error) {
commit("setError", error.message);
}
},
async fetchUserWithUid({ commit, dispatch }, {uid}) {
// 로그인은 google 계정으로 한다.
// user 정보는 mylog 계정 정보를 사용한다.
// 그러므로 구글 계정의 uid로 mylog 계정의 user 정보를 가져와야 한다.
try {
const users = [];
const userRef = query(collection(db, "users"), where('uids', 'array-contains', uid));
const querySnapshot = await getDocs(userRef);
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
users.push({ id: doc.id, ...doc.data() });
});
// 로그인 설정을 한다.
commit('setUser', users[0]);
dispatch("fetchUserInfo", users[0]);
} catch (error) {
console.error('Error fetching user:', error);
}
},
async login({ commit, dispatch }, { email, password }) {
try {
const { user } = await signInWithEmailAndPassword(auth, email, password);
//console.log('user::::', user);
// 웹앱의 계정 정보를 가져와 로그인 설정을 한다.
dispatch('fetchUserWithUid', {uid: user.uid});
router.push("/"); // home으로
} catch (error) {
commit('setError', error.message);
alert("Failed to log in: " + error.message);
}
},
async addUidToUser({ state }, newUid) {
//console.log('user.id:', state.user.id);
if (state.user) {
try {
const userDoc = doc(db, "users", state.user.id);
updateDoc(userDoc, {
uids: arrayUnion(newUid)
});
// Update the local state if neededa
state.user.uids = [...(state.user.uids || []), newUid];
} catch (error) {
console.error('Error adding UID to user:', error);
}
}
},
async addGoogleAccount({ commit, dispatch, getters }) {
try {
const provider = new GoogleAuthProvider();
const { user } = await signInWithPopup(auth, provider);
try {
// 이미 연동된 회원의 경우 알림 메시지 출력한다.
const myUser = getters.getUserByUid(user.uid);
if (myUser) {
// 이미 연동되어 있다.
commit('setError','이미 연동되어 있습니다.');
} else {
// 구글 연동을 진행한다.
dispatch('addUidToUser', user.uid);
}
} catch (error) {
commit('setError','Error adding google uid');
}
} catch (error) {
commit('setError', error.message);
}
},
async googleLogin({ commit, getters }) {
try {
// 구글 계정에 로그인
const provider = new GoogleAuthProvider();
const { user } = await signInWithPopup(auth, provider)
//const { user } = await signInWithPopup(auth); //, googleProvider);
try {
// 구글계정의 uid로 웹앱 계정의 정보를 가져옴.
// 웹앱 계정은 사이트에 접속할 때 전체 회원 정보를 로드하였으므로
// 이미 로드된 회원 리스트에서 구글 계정 uid를 가진 myUser를 가져온다.
const myUser = getters.getUserByUid(user.uid);
if (myUser) {
//console.log('myUser: ', myUser);
commit('setUser', myUser);
router.push("/"); // home으로
} else {
console.log('등록된 회원이 아닙니다.');
commit('setError', '등록된 회원이 아닙니다.');
// 이경우 회원 가입 페이지로 이동 필요
}
} catch (error) {
//console.error('Error adding user:', error);
commit('setError', error.message);
}
} catch (error) {
commit('setError', error.message);
}
},
async logout({ commit }) {
await auth.signOut();
commit('setUser', null);
router.push("/"); // home으로
},
setError({ commit }, err_message) {
commit('setError', err_message);
},
resetError({ commit }) {
commit('setError', null);
},
initializeAuth({ commit, dispatch }) {
onAuthStateChanged(auth, (user) => {
if (user) {
// user.uid로 웹앱의 firestore DB에서 계정 정보를 가져온다.
dispatch('fetchUserWithUid', {uid: user.uid});
// fetchUserWithUid에서 setUser를 실행한다.
// commit("setUser", user);
//dispatch("fetchUserInfo");
} else {
commit("setUser", null);
commit("setUserInfo", null);
}
});
},
};
const getters = {
user: state => state.user,
userInfo: state => state.userInfo,
users: state => state.users,
error: state => state.error,
isAuthenticated: state => !!state.user,
isLoading: state => state.isLoading,
getUserByUid: (state) => (uid) => {
return state.users.find(user => user.uids && user.uids.includes(uid));
}
};
export default {
namespaced: true,
state,
mutations,
actions,
getters
};
'Vue로 PWA 개발' 카테고리의 다른 글
14. myLog 페이지 - 접근 제한 (0) | 2024.10.12 |
---|---|
13. mylog 페이지 - 인증 후 보기 (5) | 2024.10.12 |
11. mylog 로그인 - google 로그인 (2) | 2024.10.11 |
10. mylog 로그인 - firebase auth (0) | 2024.10.11 |
9. mylog 로그인 (0) | 2024.10.11 |