1. 개요
이 Codelab에서는 대화형 웹 애플리케이션을 만들기 위한 Firebase 의 몇 가지 기본 사항을 알아봅니다. 여러 Firebase 제품을 사용하여 이벤트 RSVP 및 방명록 채팅 앱을 빌드합니다.
당신이 배울 것
- Firebase 인증 및 FirebaseUI로 사용자를 인증합니다.
- Cloud Firestore를 사용하여 데이터를 동기화합니다.
- 데이터베이스 보안을 위해 Firebase 보안 규칙을 작성합니다.
필요한 것
- Chrome과 같은 원하는 브라우저.
- stackblitz.com 에 액세스합니다(계정이나 로그인이 필요하지 않음).
- Gmail 계정과 같은 Google 계정. GitHub 계정에 이미 사용하고 있는 이메일 계정을 권장합니다. 이를 통해 StackBlitz의 고급 기능을 사용할 수 있습니다.
- Codelab의 샘플 코드입니다. 코드를 받는 방법은 다음 단계를 참조하세요.
2. 시작 코드 받기
이 Codelab에서는 여러 Firebase 워크플로가 통합된 온라인 편집기인 StackBlitz를 사용하여 앱을 빌드합니다. Stackblitz에는 소프트웨어 설치나 특별한 StackBlitz 계정이 필요하지 않습니다.
StackBlitz를 사용하면 다른 사람과 프로젝트를 공유할 수 있습니다. StackBlitz 프로젝트 URL이 있는 다른 사람은 코드를 보고 프로젝트를 포크할 수 있지만 StackBlitz 프로젝트를 편집할 수는 없습니다.
- 시작 코드를 보려면 다음 URL로 이동하세요. https://stackblitz.com/edit/firebase-gtk-web-start
- StackBlitz 페이지 상단에서 포크를 클릭합니다.
이제 고유한 URL과 함께 고유한 이름을 가진 고유한 StackBlitz 프로젝트로 시작 코드의 복사본을 갖게 되었습니다. 모든 파일과 변경 사항은 이 StackBlitz 프로젝트에 저장됩니다.
3. 이벤트 정보 수정
이 Codelab의 시작 자료는 일부 스타일시트와 앱용 HTML 컨테이너 몇 개를 포함하여 웹 앱의 일부 구조를 제공합니다. 이 Codelab의 뒷부분에서 이러한 컨테이너를 Firebase에 연결합니다.
시작하려면 StackBlitz 인터페이스에 좀 더 익숙해지도록 합시다.
- StackBlitz에서
index.html
파일을 엽니다. -
event-details-container
및description-container
찾은 다음 일부 이벤트 세부 정보를 편집해 보십시오.
텍스트를 편집하면 StackBlitz의 자동 페이지 다시 로드에 새 이벤트 세부 정보가 표시됩니다. 멋지죠?
<!-- ... -->
<div id="app">
<img src="..." />
<section id="event-details-container">
<h1>Firebase Meetup</h1>
<p><i class="material-icons">calendar_today</i> October 30</p>
<p><i class="material-icons">location_city</i> San Francisco</p>
</section>
<hr>
<section id="firebaseui-auth-container"></section>
<section id="description-container">
<h2>What we'll be doing</h2>
<p>Join us for a day full of Firebase Workshops and Pizza!</p>
</section>
</div>
<!-- ... -->
앱 미리보기는 다음과 같아야 합니다.
앱 미리보기
4. Firebase 프로젝트 생성 및 설정
이벤트 정보를 표시하는 것은 손님에게는 좋지만 이벤트를 표시하는 것만으로는 아무에게도 유용하지 않습니다. 이 앱에 몇 가지 동적 기능을 추가해 보겠습니다. 이를 위해서는 Firebase를 앱에 연결해야 합니다. Firebase를 시작하려면 Firebase 프로젝트를 만들고 설정해야 합니다.
Firebase 프로젝트 만들기
- Firebase 에 로그인합니다.
- Firebase 콘솔에서 프로젝트 추가 (또는 프로젝트 만들기 )를 클릭한 다음 Firebase 프로젝트의 이름을 Firebase-Web-Codelab 로 지정합니다.
- 프로젝트 생성 옵션을 클릭합니다. 메시지가 표시되면 Firebase 약관에 동의합니다. 이 앱에 Analytics를 사용하지 않을 것이므로 Google Analytics 화면에서 "사용 안 함"을 클릭하십시오.
Firebase 프로젝트에 대한 자세한 내용은 Firebase 프로젝트 이해를 참조하세요.
콘솔에서 Firebase 제품 활성화 및 설정
빌드 중인 앱은 웹 앱에 사용할 수 있는 여러 Firebase 제품을 사용합니다.
- Firebase 인증 및 Firebase UI를 통해 사용자가 앱에 쉽게 로그인할 수 있습니다.
- Cloud Firestore는 구조화된 데이터를 클라우드에 저장하고 데이터가 변경될 때 즉시 알림을 받습니다.
- 데이터베이스 보안을 위한 Firebase 보안 규칙 .
이러한 제품 중 일부는 특별한 구성이 필요하거나 Firebase 콘솔을 사용하여 활성화해야 합니다.
Firebase 인증을 위한 이메일 로그인 활성화
사용자가 웹 앱에 로그인할 수 있도록 하려면 이 Codelab에 이메일/비밀번호 로그인 방법을 사용합니다.
- Firebase 콘솔의 왼쪽 패널에서 빌드 > 인증을 클릭합니다. 그런 다음 시작하기 를 클릭합니다. 이제 가입한 사용자를 보고, 로그인 공급자를 구성하고, 설정을 관리할 수 있는 인증 대시보드에 있습니다.
- 로그인 방법 탭을 선택합니다(또는 여기를 클릭하여 탭으로 바로 이동).
- 공급자 옵션에서 이메일/비밀번호를 클릭하고 스위치를 활성화 로 전환한 다음 저장 을 클릭합니다.
Cloud Firestore 설정
웹 앱은 Cloud Firestore를 사용하여 채팅 메시지를 저장하고 새 채팅 메시지를 받습니다.
Cloud Firestore를 설정하는 방법은 다음과 같습니다.
- Firebase 콘솔의 왼쪽 패널에서 빌드 > Firestore 데이터베이스를 클릭합니다. 그런 다음 데이터베이스 생성을 클릭합니다.
- 데이터베이스 생성 을 클릭합니다.
- 테스트 모드에서 시작 옵션을 선택합니다. 보안 규칙에 대한 고지 사항을 읽으십시오. 테스트 모드에서는 개발 중에 데이터베이스에 자유롭게 쓸 수 있습니다. 다음 을 클릭합니다.
- 데이터베이스 위치를 선택합니다(기본값만 사용할 수 있음). 하지만 이 위치는 나중에 변경할 수 없습니다.
- 완료 를 클릭합니다.
5. Firebase 추가 및 구성
이제 Firebase 프로젝트를 생성하고 일부 서비스를 사용하도록 설정했으므로 Firebase를 사용하려는 코드와 사용할 Firebase 프로젝트를 알려야 합니다.
Firebase 라이브러리 추가
앱에서 Firebase를 사용하려면 앱에 Firebase 라이브러리를 추가해야 합니다. Firebase 문서에 설명된 대로 이를 수행하는 방법에는 여러 가지가 있습니다. 예를 들어 Google의 CDN에서 라이브러리를 추가하거나 Browserify를 사용하는 경우 npm을 사용하여 로컬로 설치한 다음 앱에 패키징할 수 있습니다.
StackBlitz는 자동 번들링을 제공하므로 가져오기 문을 사용하여 Firebase 라이브러리를 추가할 수 있습니다. "트리 쉐이킹"이라는 프로세스를 통해 웹 페이지의 전체 크기를 줄이는 데 도움이 되는 모듈식(v9) 버전의 라이브러리를 사용하게 됩니다. 문서에서 모듈식 SDK에 대해 자세히 알아볼 수 있습니다.
이 앱을 빌드하려면 Firebase 인증, FirebaseUI 및 Cloud Firestore 라이브러리를 사용합니다. 이 Codelab의 경우 index.js
파일 상단에 다음 가져오기 문이 이미 포함되어 있으며 진행하면서 각 Firebase 라이브러리에서 더 많은 메서드를 가져올 것입니다.
// Import stylesheets
import './style.css';
// Firebase App (the core Firebase SDK) is always required
import { initializeApp } from 'firebase/app';
// Add the Firebase products and methods that you want to use
import {} from 'firebase/auth';
import {} from 'firebase/firestore';
import * as firebaseui from 'firebaseui';
Firebase 프로젝트에 Firebase 웹 앱 추가
- Firebase 콘솔로 돌아가서 왼쪽 상단의 프로젝트 개요 를 클릭하여 프로젝트 개요 페이지로 이동합니다.
- 프로젝트 개요 페이지 중앙에서 웹 아이콘을 클릭합니다.
새 Firebase 웹 앱을 만듭니다.
- Web App 이라는 닉네임으로 앱을 등록합니다.
- 이 Codelab의 경우 Also set up Firebase Hosting for this app 옆의 체크박스를 선택하지 마세요. 지금은 StackBlitz의 미리보기 창을 사용합니다.
- 앱 등록 을 클릭합니다.
- Firebase 구성 객체를 클립보드에 복사합니다.
- 콘솔에 계속을 클릭합니다. 앱에 Firebase 구성 객체를 추가합니다.
- StackBlitz로 돌아가
index.js
파일로 이동합니다. -
Add Firebase project configuration object here
주석 행을 찾은 다음 주석 바로 아래에 구성 스니펫을 붙여넣습니다. - 고유한 Firebase 프로젝트 구성을 사용하여 Firebase를 설정하려면
initializeApp
함수 호출을 추가하세요.// ... // Add Firebase project configuration object here const firebaseConfig = { apiKey: "random-unique-string", authDomain: "your-projectId.firebaseapp.com", databaseURL: "https://your-projectId.firebaseio.com", projectId: "your-projectId", storageBucket: "your-projectId.appspot.com", messagingSenderId: "random-unique-string", appId: "random-unique-string", }; // Initialize Firebase initializeApp(firebaseConfig);
6. 사용자 로그인(RSVP) 추가
이제 앱에 Firebase를 추가했으므로 Firebase 인증을 사용하여 사람을 등록하는 RSVP 버튼을 설정할 수 있습니다.
이메일 로그인 및 FirebaseUI로 사용자 인증
사용자에게 이메일 주소로 로그인하라는 메시지를 표시하는 RSVP 버튼이 필요합니다. FirebaseUI를 RSVP 버튼에 연결하면 됩니다.FirebaseUI는 Firebase 인증 위에 미리 빌드된 UI를 제공하는 라이브러리입니다.
FirebaseUI에는 다음 두 가지 작업을 수행하는 구성( 문서 의 옵션 참조)이 필요합니다.
- 이메일/비밀번호 로그인 방법을 사용하고 싶다고 FirebaseUI에 알립니다.
- 성공적인 로그인에 대한 콜백을 처리하고 리디렉션을 피하기 위해 false를 반환합니다. 단일 페이지 웹앱을 빌드하고 있기 때문에 페이지를 새로고침하지 않으려고 합니다.
FirebaseUI 인증을 초기화하는 코드 추가
- StackBlitz에서
index.js
파일로 이동합니다. - 상단에서
firebase/auth
import 문을 찾은 다음 다음과 같이getAuth
및EmailAuthProvider
추가합니다.// ... // Add the Firebase products and methods that you want to use import { getAuth, EmailAuthProvider } from 'firebase/auth'; import {} from 'firebase/firestore';
- 다음과 같이
initializeApp
바로 뒤에 auth 개체에 대한 참조를 저장합니다.initializeApp(firebaseConfig); auth = getAuth();
- FirebaseUI 구성은 시작 코드에 이미 제공되어 있습니다. 이메일 인증 공급자를 사용하도록 이미 설정되어 있습니다.
-
index.js
의main()
함수 하단에 다음과 같이 FirebaseUI 초기화 문을 추가합니다.async function main() { // ... // Initialize the FirebaseUI widget using Firebase const ui = new firebaseui.auth.AuthUI(auth); } main();
HTML에 RSVP 버튼 추가
- StackBlitz에서
index.html
파일로 이동합니다. - 아래 예와 같이
event-details-container
내부에 RSVP 버튼용 HTML을 추가합니다.
이 Codelab의 경우index.js
파일에 이러한 특정 ID에 대한 후크가 이미 있으므로 아래와 같이 동일한id
값을 사용하도록 주의하세요.
index.html
파일에는 ID가firebaseui-auth-container
인 컨테이너가 있습니다. 이것은 로그인을 유지하기 위해 FirebaseUI에 전달할 ID입니다.
앱 미리보기<!-- ... --> <section id="event-details-container"> <!-- ... --> <!-- ADD THE RSVP BUTTON HERE --> <button id="startRsvp">RSVP</button> </section> <hr> <section id="firebaseui-auth-container"></section> <!-- ... -->
- RSVP 버튼에 리스너를 설정하고 FirebaseUI 시작 함수를 호출합니다. 이렇게 하면 FirebaseUI에 로그인 창을 보길 원한다고 알립니다.
index.js
의main()
함수 하단에 다음 코드를 추가합니다.async function main() { // ... // Listen to RSVP button clicks startRsvpButton.addEventListener("click", () => { ui.start("#firebaseui-auth-container", uiConfig); }); } main();
앱 로그인 테스트
- StackBlitz의 미리보기 창에서 RSVP 버튼을 클릭하여 앱에 로그인합니다.
- 이 Codelab에서는 이메일 확인 단계를 설정하지 않으므로 가짜 이메일 주소를 포함한 모든 이메일 주소를 사용할 수 있습니다.
-
auth/operation-not-allowed
또는The given sign-in provider is disabled for this Firebase project
오류 메시지가 표시되면 Firebase Console에서 이메일/비밀번호를 로그인 제공자로 사용 설정했는지 확인하세요.
- Firebase 콘솔에서 인증 대시보드 로 이동합니다. 사용자 탭에 앱에 로그인하기 위해 입력한 계정 정보가 표시되어야 합니다.
UI에 인증 상태 추가
다음으로, UI가 로그인 사실을 반영하는지 확인하십시오.
사용자의 로그인 상태가 변경될 때마다 알림을 받는 Firebase 인증 상태 리스너 콜백을 사용합니다. 현재 로그인한 사용자가 있는 경우 앱에서 "RSVP" 버튼을 "로그아웃" 버튼으로 전환합니다.
- StackBlitz에서
index.js
파일로 이동합니다. - 상단에서
firebase/auth
import 문을 찾은 다음
와 같이// ... // Add the Firebase products and methods that you want to use import { getAuth, EmailAuthProvider, signOut, onAuthStateChanged } from 'firebase/auth'; import {} from 'firebase/firestore';
signOut
및onAuthStateChanged
추가합니다. -
main()
함수 맨 아래에 다음 코드를 추가합니다.async function main() { // ... // Listen to the current Auth state onAuthStateChanged(auth, user => { if (user) { startRsvpButton.textContent = 'LOGOUT'; } else { startRsvpButton.textContent = 'RSVP'; } }); } main();
- 버튼 리스너에서 현재 사용자가 있는지 확인하고 로그아웃합니다. 이렇게 하려면 현재
startRsvpButton.addEventListener
다음으로 바꿉니다.// ... // Called when the user clicks the RSVP button startRsvpButton.addEventListener('click', () => { if (auth.currentUser) { // User is signed in; allows user to sign out signOut(auth); } else { // No user is signed in; allows user to sign in ui.start('#firebaseui-auth-container', uiConfig); } });
이제 앱의 버튼에 LOGOUT 이 표시되고 클릭하면 RSVP 로 다시 전환됩니다.
앱 미리보기
7. Cloud Firestore에 메시지 쓰기
사용자가 오고 있다는 사실을 아는 것도 좋지만 게스트가 앱에서 할 수 있는 다른 작업을 제공하겠습니다. 방명록에 메시지를 남길 수 있다면 어떨까요? 그들은 왜 오고 싶은지 또는 누구를 만나고 싶은지 공유할 수 있습니다.
사용자가 앱에서 작성하는 채팅 메시지를 저장하려면 Cloud Firestore를 사용합니다.
데이터 모델
Cloud Firestore는 NoSQL 데이터베이스이며 데이터베이스에 저장된 데이터는 컬렉션, 문서, 필드 및 하위 컬렉션으로 분할됩니다. 채팅의 각 메시지를 guestbook
이라는 최상위 컬렉션에 문서로 저장합니다.
Firestore에 메시지 추가
이 섹션에서는 사용자가 데이터베이스에 새 메시지를 쓰는 기능을 추가합니다. 먼저 UI 요소(메시지 필드 및 보내기 버튼)에 대한 HTML을 추가합니다. 그런 다음 이러한 요소를 데이터베이스에 연결하는 코드를 추가합니다.
메시지 필드 및 보내기 버튼의 UI 요소를 추가하려면:
- StackBlitz에서
index.html
파일로 이동합니다. -
guestbook-container
찾은 후 다음 HTML을 추가하여 메시지 입력 필드와 보내기 버튼이 있는 양식을 만듭니다.<!-- ... --> <section id="guestbook-container"> <h2>Discussion</h2> <form id="leave-message"> <label>Leave a message: </label> <input type="text" id="message"> <button type="submit"> <i class="material-icons">send</i> <span>SEND</span> </button> </form> </section> <!-- ... -->
앱 미리보기
SEND 버튼을 클릭하는 사용자는 아래의 코드 스니펫을 트리거합니다. 메시지 입력 필드의 내용을 데이터베이스의 guestbook
모음에 추가합니다. 특히 addDoc
메서드는 guestbook
컬렉션에 새 문서(자동으로 생성된 ID 포함)에 메시지 콘텐츠를 추가합니다.
- StackBlitz에서
index.js
파일로 이동합니다. - 상단에서
firebase/firestore
import 문을 찾은 다음 다음과 같이getFirestore
,addDoc
및collection
추가합니다.// ... // Add the Firebase products and methods that you want to use import { getAuth, EmailAuthProvider, signOut, onAuthStateChanged } from 'firebase/auth'; import { getFirestore, addDoc, collection } from 'firebase/firestore';
- 이제
initializeApp
직후 Firestoredb
개체에 대한 참조를 저장합니다.initializeApp(firebaseConfig); auth = getAuth(); db = getFirestore();
-
main()
함수 하단에 다음 코드를 추가합니다.
auth.currentUser.uid
로그인한 모든 사용자에게 Firebase 인증이 제공하는 자동 생성 고유 ID에 대한 참조입니다.async function main() { // ... // Listen to the form submission form.addEventListener('submit', async e => { // Prevent the default form redirect e.preventDefault(); // Write a new message to the database collection "guestbook" addDoc(collection(db, 'guestbook'), { text: input.value, timestamp: Date.now(), name: auth.currentUser.displayName, userId: auth.currentUser.uid }); // clear message input field input.value = ''; // Return false to avoid redirect return false; }); } main();
로그인한 사용자에게만 방명록 표시
당신은 아무나 손님의 채팅을 보는 것을 원하지 않습니다. 채팅 보안을 위해 할 수 있는 한 가지는 로그인한 사용자만 방명록을 볼 수 있도록 허용하는 것입니다. 즉, 자체 앱의 경우 Firebase 보안 규칙 으로 데이터베이스를 보호해야 합니다. (Codelab 뒷부분에 보안 규칙에 대한 자세한 정보가 있습니다.)
- StackBlitz에서
index.js
파일로 이동합니다. -
onAuthStateChanged
리스너를 편집하여 방명록을 숨기고 표시합니다.// ... // Listen to the current Auth state onAuthStateChanged(auth, user => { if (user) { startRsvpButton.textContent = 'LOGOUT'; // Show guestbook to logged-in users guestbookContainer.style.display = 'block'; } else { startRsvpButton.textContent = 'RSVP'; // Hide guestbook for non-logged-in users guestbookContainer.style.display = 'none'; } });
테스트 전송 메시지
- 앱에 로그인되어 있는지 확인하세요.
- "안녕하세요!"와 같은 메시지를 입력한 다음 보내기를 클릭합니다.
이 작업은 Cloud Firestore 데이터베이스에 메시지를 씁니다. 그러나 여전히 데이터 검색을 구현해야 하므로 실제 웹 앱에는 아직 메시지가 표시되지 않습니다. 다음에 그렇게 할 것입니다.
그러나 Firebase 콘솔에서 새로 추가된 메시지를 볼 수 있습니다.
Firebase 콘솔의 Firestore 데이터베이스 대시보드 에 새로 추가된 메시지와 함께 guestbook
모음이 표시되어야 합니다. 메시지를 계속 보내면 방명록 컬렉션에 다음과 같은 많은 문서가 포함됩니다.
Firebase 콘솔
8. 메시지 읽기
메시지 동기화
게스트가 데이터베이스에 메시지를 작성할 수 있지만 아직 앱에서 메시지를 볼 수 없다는 것은 멋진 일입니다.
메시지를 표시하려면 데이터가 변경될 때 트리거하는 리스너를 추가한 다음 새 메시지를 표시하는 UI 요소를 만들어야 합니다.
앱에서 새로 추가된 메시지를 수신 대기하는 코드를 추가합니다. 먼저 HTML에 섹션을 추가하여 메시지를 표시합니다.
- StackBlitz에서
index.html
파일로 이동합니다. -
guestbook-container
에서 ID가guestbook
인 새 섹션을 추가합니다.<!-- ... --> <section id="guestbook-container"> <h2>Discussion</h2> <form><!-- ... --></form> <section id="guestbook"></section> </section> <!-- ... -->
다음으로 데이터에 대한 변경 사항을 수신 대기하는 리스너를 등록합니다.
- StackBlitz에서
index.js
파일로 이동합니다. - 상단에서
firebase/firestore
가져오기 문을 찾은 다음
과 같이// ... import { getFirestore, addDoc, collection, query, orderBy, onSnapshot } from 'firebase/firestore';
query
,orderBy
및onSnapshot
추가합니다. -
main()
함수 맨 아래에 다음 코드를 추가하여 데이터베이스의 모든 문서(방명록 메시지)를 반복합니다. 이 코드에서 일어나는 일에 대해 자세히 알아보려면 스니펫 아래의 정보를 읽으십시오.async function main() { // ... // Create query for messages const q = query(collection(db, 'guestbook'), orderBy('timestamp', 'desc')); onSnapshot(q, snaps => { // Reset page guestbook.innerHTML = ''; // Loop through documents in database snaps.forEach(doc => { // Create an HTML entry for each document and add it to the chat const entry = document.createElement('p'); entry.textContent = doc.data().name + ': ' + doc.data().text; guestbook.appendChild(entry); }); }); } main();
데이터베이스의 메시지를 듣기 위해 collection
기능을 사용하여 특정 컬렉션에 대한 쿼리를 만들었습니다. 위의 코드는 채팅 메시지가 저장되는 guestbook
컬렉션의 변경 사항을 수신합니다. 메시지는 최신 메시지를 맨 위에 표시하기 위해 orderBy('timestamp', 'desc')
사용하여 날짜별로 정렬됩니다.
onSnapshot
함수는 사용할 쿼리와 콜백 함수라는 두 가지 매개변수를 사용합니다. 콜백 함수는 쿼리와 일치하는 문서에 변경 사항이 있을 때 트리거됩니다. 메시지가 삭제, 수정 또는 추가된 경우일 수 있습니다. 자세한 내용은 Cloud Firestore 문서를 참조하세요.
테스트 동기화 메시지
Cloud Firestore는 데이터베이스에 가입한 클라이언트와 데이터를 자동으로 즉시 동기화합니다.
- 이전에 데이터베이스에서 생성한 메시지가 앱에 표시되어야 합니다. 자유롭게 새 메시지를 작성하십시오. 즉시 나타나야 합니다.
- 여러 창이나 탭에서 작업 공간을 열면 메시지가 여러 탭에서 실시간으로 동기화됩니다.
- (선택 사항) Firebase 콘솔의 데이터베이스 섹션에서 직접 새 메시지를 수동으로 삭제, 수정 또는 추가할 수 있습니다. 모든 변경 사항이 UI에 표시되어야 합니다.
축하해요! 앱에서 Cloud Firestore 문서를 읽고 있습니다!
앱 미리보기
9. 기본 보안 규칙 설정
처음에 테스트 모드를 사용하도록 Cloud Firestore를 설정했습니다. 즉, 데이터베이스가 읽기 및 쓰기를 위해 열려 있음을 의미합니다. 그러나 테스트 모드는 개발 초기 단계에서만 사용해야 합니다. 가장 좋은 방법은 앱을 개발할 때 데이터베이스에 대한 보안 규칙을 설정하는 것입니다. 보안은 앱의 구조와 동작에 통합되어야 합니다.
보안 규칙을 사용하면 데이터베이스의 문서 및 컬렉션에 대한 액세스를 제어할 수 있습니다. 유연한 규칙 구문을 사용하면 전체 데이터베이스에 대한 모든 쓰기에서 특정 문서에 대한 작업에 이르기까지 모든 항목과 일치하는 규칙을 만들 수 있습니다.
Firebase 콘솔에서 Cloud Firestore에 대한 보안 규칙을 작성할 수 있습니다.
- Firebase Console의 Build 섹션에서 Firestore Database를 클릭한 다음 Rules 탭을 선택합니다(또는 여기를 클릭하여 Rules 탭으로 직접 이동).
- 오늘부터 몇 주 후에 공개 액세스 시간 제한이 있는 다음과 같은 기본 보안 규칙이 표시되어야 합니다.
컬렉션 식별
먼저 앱이 데이터를 쓰는 컬렉션을 식별합니다.
- 기존
match /{document=**}
절을 삭제하여 규칙이 다음과 같이 표시되도록 합니다.rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { } }
-
match /databases/{database}/documents
에서 보안하려는 컬렉션을 식별합니다:rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /guestbook/{entry} { // You'll add rules here in the next step. } }
보안 규칙 추가
인증 UID를 각 방명록 문서의 필드로 사용했기 때문에 인증 UID를 가져오고 문서에 쓰려고 시도하는 사람이 일치하는 인증 UID를 가지고 있는지 확인할 수 있습니다.
- 아래와 같이 규칙
에 읽기 및 쓰기 규칙을 추가합니다.rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /guestbook/{entry} { allow read: if request.auth.uid != null; allow create: if request.auth.uid == request.resource.data.userId; } } }
- 게시를 클릭하여 새 규칙을 배포합니다. 이제 방명록의 경우 로그인한 사용자만 메시지(모든 메시지!)를 읽을 수 있지만 사용자 ID를 사용해서만 메시지를 만들 수 있습니다. 또한 메시지를 편집하거나 삭제할 수 없습니다.
유효성 검사 규칙 추가
- 모든 예상 필드가 문서에 있는지 확인하기 위해 데이터 유효성 검사를 추가합니다.
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /guestbook/{entry} { allow read: if request.auth.uid != null; allow create: if request.auth.uid == request.resource.data.userId && "name" in request.resource.data && "text" in request.resource.data && "timestamp" in request.resource.data; } } }
- 게시를 클릭하여 새 규칙을 배포합니다.
리스너 재설정
이제 앱에서 인증된 사용자만 로그인할 수 있으므로 인증 리스너 내에서 방명록 firestore
쿼리를 이동해야 합니다. 그렇지 않으면 권한 오류가 발생하고 사용자가 로그아웃할 때 앱 연결이 끊어집니다.
- StackBlitz에서
index.js
파일로 이동합니다. - 방명록 컬렉션
onSnapshot
수신기를subscribeGuestbook
이라는 새 함수로 가져옵니다. 또한onSnapshot
함수의 결과를guestbookListener
변수에 할당합니다.
FirestoreonSnapshot
리스너는 나중에 스냅샷 리스너를 취소하는 데 사용할 수 있는 구독 취소 기능을 반환합니다 .// ... // Listen to guestbook updates function subscribeGuestbook() { const q = query(collection(db, 'guestbook'), orderBy('timestamp', 'desc')); guestbookListener = onSnapshot(q, snaps => { // Reset page guestbook.innerHTML = ''; // Loop through documents in database snaps.forEach(doc => { // Create an HTML entry for each document and add it to the chat const entry = document.createElement('p'); entry.textContent = doc.data().name + ': ' + doc.data().text; guestbook.appendChild(entry); }); }); }
-
unsubscribeGuestbook
아래에 새 함수를 추가합니다.guestbookListener
변수가 null이 아닌지 확인한 다음 함수를 호출하여 리스너를 취소합니다.// ... // Unsubscribe from guestbook updates function unsubscribeGuestbook() { if (guestbookListener != null) { guestbookListener(); guestbookListener = null; } }
마지막으로 onAuthStateChanged
콜백에 새 함수를 추가합니다.
-
if (user)
의 하단에subscribeGuestbook()
추가하세요. -
else
문의 맨 아래에unsubscribeGuestbook()
추가합니다.// ... // Listen to the current Auth state onAuthStateChanged(auth, user => { if (user) { startRsvpButton.textContent = 'LOGOUT'; // Show guestbook to logged-in users guestbookContainer.style.display = 'block'; // Subscribe to the guestbook collection subscribeGuestbook(); } else { startRsvpButton.textContent = 'RSVP'; // Hide guestbook for non-logged-in users guestbookContainer.style.display = 'none'; // Unsubscribe from the guestbook collection unsubscribeGuestbook(); } });
10. 보너스 단계: 배운 내용 연습하기
참석자의 RSVP 상태 기록
현재 귀하의 앱은 사람들이 이벤트에 관심이 있는 경우에만 채팅을 시작할 수 있도록 허용합니다. 또한 누군가 오는지 알 수 있는 유일한 방법은 채팅에 게시하는 것입니다. 정리하고 얼마나 많은 사람들이 오는지 사람들에게 알리자.
토글을 추가하여 이벤트에 참석하고 싶은 사람을 등록한 다음 참석하는 사람의 수를 수집합니다.
- StackBlitz에서
index.html
파일로 이동합니다. -
guestbook-container
에서 다음과 같이 YES 및 NO 버튼 세트를 추가합니다.<!-- ... --> <section id="guestbook-container"> <h2>Are you attending?</h2> <button id="rsvp-yes">YES</button> <button id="rsvp-no">NO</button> <h2>Discussion</h2> <!-- ... --> </section> <!-- ... -->
앱 미리보기
다음으로 버튼 클릭에 대한 리스너를 등록합니다. 사용자가 예를 클릭하면 인증 UID를 사용하여 응답을 데이터베이스에 저장합니다.
- StackBlitz에서
index.js
파일로 이동합니다. - 상단에서
firebase/firestore
import 문을 찾은 다음
과 같이// ... // Add the Firebase products and methods that you want to use import { getFirestore, addDoc, collection, query, orderBy, onSnapshot, doc, setDoc, where } from 'firebase/firestore';
doc
,setDoc
,where
추가합니다. -
main()
함수 맨 아래에 다음 코드를 추가하여 RSVP 상태를 수신합니다.async function main() { // ... // Listen to RSVP responses rsvpYes.onclick = async () => { }; rsvpNo.onclick = async () => { }; } main();
- 다음으로
attendees
라는 새 컬렉션을 만든 다음 RSVP 버튼을 클릭하면 문서 참조를 등록합니다. 클릭한 버튼에 따라 해당 참조를true
또는false
으로 설정합니다.
먼저rsvpYes
의 경우:
그런 다음// ... // Listen to RSVP responses rsvpYes.onclick = async () => { // Get a reference to the user's document in the attendees collection const userRef = doc(db, 'attendees', auth.currentUser.uid); // If they RSVP'd yes, save a document with attendi()ng: true try { await setDoc(userRef, { attending: true }); } catch (e) { console.error(e); } };
rsvpNo
의 경우에도 동일하지만 값이false
인 경우:rsvpNo.onclick = async () => { // Get a reference to the user's document in the attendees collection const userRef = doc(db, 'attendees', auth.currentUser.uid); // If they RSVP'd yes, save a document with attending: true try { await setDoc(userRef, { attending: false }); } catch (e) { console.error(e); } };
보안 규칙 업데이트
이미 몇 가지 규칙이 설정되어 있기 때문에 버튼으로 추가하는 새 데이터는 거부됩니다.
attendees
컬렉션 에 추가 허용
attendees
컬렉션에 추가할 수 있도록 규칙을 업데이트해야 합니다.
-
attendees
수집의 경우 인증 UID를 문서 이름으로 사용했으므로 제출자의uid
작성 중인 문서와 동일한지 확인할 수 있습니다. 모든 사람이 참석자 목록을 읽을 수 있도록 허용하지만(개인 데이터가 없기 때문에) 생성자만 업데이트할 수 있어야 합니다.rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // ... // match /attendees/{userId} { allow read: if true; allow write: if request.auth.uid == userId; } } }
- 게시를 클릭하여 새 규칙을 배포합니다.
유효성 검사 규칙 추가
- 모든 예상 필드가 문서에 있는지 확인하기 위해 몇 가지 데이터 유효성 검사 규칙을 추가합니다.
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // ... // match /attendees/{userId} { allow read: if true; allow write: if request.auth.uid == userId && "attending" in request.resource.data; } } }
- 게시를 클릭하여 규칙을 배포하는 것을 잊지 마세요!
(선택 사항) 이제 버튼을 클릭한 결과를 볼 수 있습니다. Firebase 콘솔에서 Cloud Firestore 대시보드로 이동합니다.
RSVP 상태 읽기
이제 응답을 기록했으므로 누가 오는지 확인하고 UI에 반영해 보겠습니다.
- StackBlitz에서
index.html
파일로 이동합니다. -
description-container
에서 ID가number-attending
인 새 요소를 추가합니다.<!-- ... --> <section id="description-container"> <!-- ... --> <p id="number-attending"></p> </section> <!-- ... -->
다음으로 attendees
컬렉션에 대한 리스너를 등록하고 YES 응답 수를 계산합니다.
- StackBlitz에서
index.js
파일로 이동합니다. -
main()
함수 맨 아래에 다음 코드를 추가하여 RSVP 상태를 수신하고 YES 클릭을 계산합니다.async function main() { // ... // Listen for attendee list const attendingQuery = query( collection(db, 'attendees'), where('attending', '==', true) ); const unsubscribe = onSnapshot(attendingQuery, snap => { const newAttendeeCount = snap.docs.length; numberAttending.innerHTML = newAttendeeCount + ' people going'; }); } main();
마지막으로 현재 상태에 해당하는 버튼을 강조 표시하겠습니다.
- 현재 인증 UID에
attendees
컬렉션에 항목이 있는지 확인하는 기능을 만든 다음 버튼 클래스를clicked
로 설정합니다.// ... // Listen for attendee list function subscribeCurrentRSVP(user) { const ref = doc(db, 'attendees', user.uid); rsvpListener = onSnapshot(ref, doc => { if (doc && doc.data()) { const attendingResponse = doc.data().attending; // Update css classes for buttons if (attendingResponse) { rsvpYes.className = 'clicked'; rsvpNo.className = ''; } else { rsvpYes.className = ''; rsvpNo.className = 'clicked'; } } }); }
- 그리고 구독취소 기능도 만들어 봅시다. 사용자가 로그아웃할 때 사용됩니다.
// ... function unsubscribeCurrentRSVP() { if (rsvpListener != null) { rsvpListener(); rsvpListener = null; } rsvpYes.className = ''; rsvpNo.className = ''; }
- 인증 수신기에서 함수를 호출합니다.
// ... // Listen to the current Auth state // Listen to the current Auth state onAuthStateChanged(auth, user => { if (user) { startRsvpButton.textContent = 'LOGOUT'; // Show guestbook to logged-in users guestbookContainer.style.display = 'block'; // Subscribe to the guestbook collection subscribeGuestbook(); // Subcribe to the user's RSVP subscribeCurrentRSVP(user); } else { startRsvpButton.textContent = 'RSVP'; // Hide guestbook for non-logged-in users guestbookContainer.style.display = 'none' ; // Unsubscribe from the guestbook collection unsubscribeGuestbook(); // Unsubscribe from the guestbook collection unsubscribeCurrentRSVP(); } });
- 여러 사용자로 로그인을 시도하고 YES 버튼을 추가로 클릭할 때마다 카운트가 증가하는 것을 확인하십시오.
앱 미리보기
11. 축하합니다!
Firebase를 사용하여 대화형 실시간 웹 애플리케이션을 구축했습니다!
우리가 다룬 내용
- Firebase 인증
- FirebaseUI
- 클라우드 파이어스토어
- Firebase 보안 규칙
다음 단계
- Firebase 개발자 워크플로에 대해 자세히 알아보고 싶으신가요? 앱을 완전히 로컬에서 테스트하고 실행하는 방법을 알아보려면 Firebase 에뮬레이터 Codelab을 확인하세요.
- 다른 Firebase 제품에 대해 자세히 알아보고 싶으신가요? 사용자가 업로드한 이미지 파일을 저장하고 싶으신가요? 아니면 사용자에게 알림을 보내시겠습니까? 더 많은 웹용 Firebase 제품에 대해 자세히 알아보는 Codelab은 Firebase 웹 Codelab을 확인하세요.
- Cloud Firestore에 대해 자세히 알아보고 싶으신가요? 하위 수집 및 트랜잭션에 대해 배우고 싶습니까? Cloud Firestore에 대해 자세히 알아보려면 Cloud Firestore 웹 코드랩 으로 이동하세요. 또는 이 YouTube 시리즈를 확인하여 Cloud Firestore에 대해 알아보세요 !
더 알아보기
- Firebase 사이트: firebase.google.com
- Firebase YouTube 채널
어떻게 됐어?
여러분의 피드백을 환영합니다! 여기에서 (매우) 짧은 양식을 작성하십시오.