store/modules/auth.js
// src/store/modules/auth.js
import router from '@/router'; // Vue Router import
import { auth, db, collection, doc, getDocs, addDoc, updateDoc, arrayUnion, query, where } from "@/firebase";
import { createUserWithEmailAndPassword, signInWithEmailAndPassword, onAuthStateChanged, sendPasswordResetEmail,
EmailAuthProvider, reauthenticateWithCredential, updatePassword, GoogleAuthProvider, signInWithPopup } from "firebase/auth";
const state = {
isLoading: false,
error: null,
user: null, // 현재 로그인한 회원
users: [], // 전체 회원 정보
};
const mutations = {
setLoading(state, isLoading) {
state.isLoading = isLoading;
},
setError(state, error) {
state.error = error;
},
setUser(state, user) {
state.user = user;
},
setUsers(state, users) {
state.users = users;
},
};
const actions = {
// -- 앱을 시작하면 자동 로그인을 설정한다.
async initializeAuth({ commit, dispatch }) {
onAuthStateChanged(auth, (user) => {
if (user) {
// user.uid로 웹앱의 firestore DB에서 계정 정보를 가져온다.
dispatch('fetchUserWithUid', {uid: user.uid});
} else {
commit("setUser", null);
}
});
},
// 전체 회원 정보를 로드한다.
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);
} finally {
commit('setLoading', false);
}
},
// -- 계정 만들기
async register({ commit, dispatch }, { email, password, username, mylogname }) {
try {
const userCredential = await createUserWithEmailAndPassword(auth, email, password);
const uid = userCredential.user.uid;
// Save additional user data to Firestore
const userRef = collection(db, "users");
const newUser = await addDoc(userRef, {
email: email,
uids: [uid],
username: username,
mylogname: mylogname
});
// 로그인 설정
commit('setUser', newUser);
dispatch('fetchUsers');
router.push("/"); // home으로
} catch (error) {
commit("setError", error.message);
}
},
// -- 로그인
async login({ commit, dispatch }, { email, password }) {
try {
const { user } = await signInWithEmailAndPassword(auth, email, password);
// 웹앱의 계정 정보를 가져와 로그인 설정을 한다.
dispatch('fetchUserWithUid', {uid: user.uid});
router.push("/"); // home으로
} catch (error) {
//commit('setError', error.message);
alert("Failed to log in: " + error.message);
}
},
// 로그인은 google 계정으로 한다.user 정보는 mylog 계정 정보를 사용한다.
// 그러므로 구글 계정의 uid로 mylog 계정의 user 정보를 가져와야 한다.
async fetchUserWithUid({ commit, dispatch }, {uid}) {
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]);
} catch (error) {
console.error('Error fetching user:', error);
}
},
// 로그아웃 --
async logout({ commit }) {
await auth.signOut();
commit('setUser', null);
},
// 비밀번호 재설정
async PasswordReset({}, email) {
console.log(email);
sendPasswordResetEmail(auth, email)
.then(() => {
alert("비밀번호 재설정 이메일이 발송되었습니다.");
})
.catch((error) => {
alert("비밀번호 재설정 이메일 발송 중 오류 발생:", error);
});
},
// 비밀번호 변경
async changePassword({}, { oldPassword, newPassword }) {
const credential = EmailAuthProvider.credential(
auth.currentUser.email,
oldPassword
);
reauthenticateWithCredential(auth.currentUser, credential)
.then(() => {
updatePassword(auth.currentUser, newPassword)
.then(() => {
alert("비밀번호가 성공적으로 변경되었습니다.");
}).catch((error) => {
alert("비밀번호 변경 실패 : " + error.message);
});
})
.catch((error) => {
alert("재인증 실패 : " + error.message);
});
},
// 계정 정보 수정
async updateUserInfo({ commit }, updatedInfo) {
try {
const userDoc = doc(db, "users", updatedInfo.id);
await updateDoc(userDoc, updatedInfo);
commit("setUser", updatedInfo);
alert("계정 정보를 수정하였습니다.");
} catch (error) {
alert("계정 정보 수정 실패: " + error.message);
}
},
async addGoogleAccount({ commit, dispatch, getters }) {
try {
const provider = new GoogleAuthProvider();
const { user } = await signInWithPopup(auth, provider);
try {
// 이미 연동된 회원의 경우 알림 메시지 출력한다.
const uid = user.uid;
const myUser = state.users.find(user => user.uids && user.uids.includes(uid));
if (myUser) {
// 이미 연동되어 있다.
alert('이미 연동되어 있습니다.');
} else {
// 구글 연동을 진행한다.
dispatch('addUidToUser', user.uid);
}
} catch (error) {
commit('setError','Error adding google uid');
}
} catch (error) {
commit('setError', error.message);
}
},
// 구글 계정의 uid를 받아 user collection의 uids에 넣는다.
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 googleLogin({ commit }) {
try {
// 구글 계정에 로그인
const provider = new GoogleAuthProvider();
const { user } = await signInWithPopup(auth, provider);
// 구글계정의 uid로 웹앱 계정의 정보를 가져옴.
// 웹앱 계정은 사이트에 접속할 때 전체 회원 정보를 로드하였으므로
// 이미 로드된 회원 리스트에서 구글 계정 uid를 가진 myUser를 가져온다.
const uid = user.uid;
const myUser = state.users.find(user => user.uids && user.uids.includes(uid));
if (myUser) {
commit('setUser', myUser);
router.push("/"); // home으로
} else {
alert('등록된 회원이 아닙니다.');
}
} catch (error) {
commit('setError', error.message);
}
},
resetError({ commit }) {
commit('setError', null);
},
};
const getters = {
isLoading: state => state.isLoading,
error: state => state.error,
user: state => state.user,
users: state => state.users,
};
export default {
namespaced: true,
state,
mutations,
actions,
getters
};