로그인한 사용자만 채팅방 접근 가능하게 만들기!
Firebase Auth 상태를 확인해서 로그인한 사용자만 채팅방에 접근가능하도록 합니다.
1. Firebase에서 로그인 상태 확인
Vue Router의 beforeEach 훅을 이용해서, 로그인하지 않은 사용자는 /chat에 접근할 수 없도록 설정할 거야.
🔥 onAuthStateChanged란?
onAuthStateChanged는 Firebase Authentication에서 제공하는 사용자 인증 상태 감지 함수입니다.
즉, 로그인, 로그아웃, 회원가입 등 사용자 인증 상태 변화를 실시간으로 감지할 수 있습니다.
// src/router.js
import { createRouter, createWebHistory } from "vue-router";
import AuthView from "@/views/AuthView.vue";
import ChatView from "@/views/ChatView.vue";
import { getAuth, onAuthStateChanged } from "firebase/auth";
const routes = [
{ path: "/", component: AuthView },
{ path: "/chat", component: ChatView, meta: { requiresAuth: true } },
];
const router = createRouter({
history: createWebHistory(),
routes,
});
// 네비게이션 가드 추가 (로그인한 사용자만 채팅방 접근 가능)
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth) {
const auth = getAuth();
onAuthStateChanged(auth, (user) => {
if (user) {
next();
} else {
next("/");
}
});
} else {
next();
}
});
export default router;
2. Firestore에 채팅 데이터 저장 구조
Firestore에 채팅 데이터를 저장할 거야.
1:1 채팅을 위해 다음과 같은 구조를 사용하자.
/chats/{chatId}/messages/{messageId}
각 1:1 채팅은 고유한 chatId를 가지며, 그 안에 메시지가 저장됨.
// 채팅 메시지 전송
const sendMessage = async (chatId, sender, message) => {
const messagesRef = collection(db, `chats/${chatId}/messages`);
console.log(messagesRef);
await addDoc(messagesRef, {
sender,
message,
timestamp: new Date(),
});
};
3. 채팅 데이터 Firestore에 저장
firebase.js에 Firestore 관련 로직을 추가하자
// src/firebase.js
import { initializeApp } from "firebase/app";
import { getAuth, createUserWithEmailAndPassword,
signInWithEmailAndPassword, signOut } from "firebase/auth";
import { getFirestore, initializeFirestore, collection, addDoc, query,
where, getDocs, orderBy} from "firebase/firestore";
const firebaseConfig = {
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
appId: import.meta.env.VITE_FIREBASE_APP_ID,
databaseURL: import.meta.env.VITE_FIREBASE_DATABASE_URL,
};
console.log(import.meta.env.VITE_FIREBASE_PROJECT_ID);
// Firebase 초기화
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore(app);
// 회원가입 함수
const register = (email, password) => {
return createUserWithEmailAndPassword(auth, email, password);
};
// 로그인 함수
const login = (email, password) => {
return signInWithEmailAndPassword(auth, email, password);
};
// 로그아웃 함수
const logout = () => {
return signOut(auth);
};
// 특정 유저와의 1:1 채팅 찾기 또는 생성
const getOrCreateChat = async (user1, user2) => {
const chatRef = collection(db, "chats");
const q = query(chatRef, where("users", "array-contains", user1));
const snapshot = await getDocs(q);
for (const doc of snapshot.docs) {
const chatData = doc.data();
if (chatData.users.includes(user2)) {
return doc.id; // 기존 채팅방 ID 반환
}
}
// 새로운 채팅방 생성
const newChat = await addDoc(chatRef, { users: [user1, user2] });
return newChat.id;
};
// 채팅 메시지 전송
const sendMessage = async (chatId, sender, message) => {
const messagesRef = collection(db, `chats/${chatId}/messages`);
console.log(messagesRef);
await addDoc(messagesRef, {
sender,
message,
timestamp: new Date(),
});
};
export { auth, db, register, login, logout,
getOrCreateChat, sendMessage
};
추가된 기능:
✔️ getOrCreateChat(user1, user2) → 기존 1:1 채팅방을 찾거나 새로 생성
✔️ sendMessage(chatId, sender, message) → Firestore에 채팅 메시지 저장
4. 채팅 UI 추가
이제 1:1 채팅 UI를 만들어보자.
src/views/ChatView.vue에 다음과 같이 코드를 추가해.
<!-- src/views/ChatView.vue -->
<template>
<v-container class="fill-height d-flex flex-column">
<v-card class="pa-5" width="400">
<v-card-title class="text-center text-h5">1:1 채팅</v-card-title>
<v-select v-model="selectedUser" :items="users" label="대화 상대 선택" />
<v-divider class="my-2"></v-divider>
<v-list v-if="messages.length > 0">
<v-list-item v-for="msg in messages" :key="msg.id">
<v-list-item-title>
<strong>{{ msg.sender === currentUser ? "나" : "상대" }}:</strong>
{{ msg.message }}
</v-list-item-title>
</v-list-item>
</v-list>
<v-text-field v-model="newMessage" label="메시지 입력" @keyup.enter="handleSendMessage" />
<v-btn color="primary" block class="mt-3" @click="handleSendMessage">전송</v-btn>
<v-btn color="red" block class="mt-3" @click="handleLogout">로그아웃</v-btn>
</v-card>
</v-container>
</template>
<script>
import { ref, watch } from "vue";
import { auth, getOrCreateChat, sendMessage } from "@/firebase";
import { useRouter } from "vue-router";
export default {
setup() {
const router = useRouter();
const currentUser = auth.currentUser?.email;
const selectedUser = ref(""); // 대화할 사용자 선택
const users = ref(["user1@example.com", "user2@example.com"]); // 예제 사용자 리스트
const chatId = ref(null);
const newMessage = ref("");
const messages = ref([]);
// 로그아웃
const handleLogout = async () => {
await auth.signOut();
router.push("/");
};
// 메시지 전송
const handleSendMessage = async () => {
if (newMessage.value.trim() === "" || !chatId.value) return;
await sendMessage(chatId.value, currentUser, newMessage.value);
newMessage.value = "";
};
// 채팅방 변경 감지
watch(selectedUser, async (newUser) => {
if (newUser) {
chatId.value = await getOrCreateChat(currentUser, newUser);
}
});
return { selectedUser, users, newMessage, handleSendMessage, messages, handleLogout, currentUser };
},
};
</script>
✅ 추가된 기능
✔️ selectedUser를 선택하면 1:1 채팅방 자동 생성
✔️ handleSendMessage()로 Firestore에 메시지 저장
✔️ watch(selectedUser, ...)로 채팅방 자동 변경
5. 실행 및 테스트
npm run dev

'Vue3, Firebase 프로젝트 - 채팅앱 VSignal' 카테고리의 다른 글
23. [개발] 실시간 메시지 업데이트 분석 - Vue3 Firebase 프로젝트 채팅앱 VSignal (0) | 2025.04.05 |
---|---|
22. [개발] 실시간 메시지 업데이트 - Vue3 Firebase 프로젝트 채팅앱 VSignal (0) | 2025.04.03 |
20. [개발] 로그인 후 채팅방 이동 - Vue3 Firebase 프로젝트 채팅앱 VSignal (0) | 2025.04.01 |
8. Pinia에서의 Composition API 스타일과 Options API 스타일 (0) | 2025.03.30 |
7. Pinia Store에서 ref와 reactive를 사용하는 방법 (0) | 2025.03.30 |