1. 만들 항목
이 Codelab에서는 최신 Angular 라이브러리인 AngularFire를 사용하여 실시간 공동작업 지도와 함께 여행 블로그를 빌드합니다. 최종 웹 앱은 여행 블로그로 구성되며, 여기에서 여행한 각 위치에 이미지를 업로드할 수 있습니다.
AngularFire는 웹 앱을 빌드하는 데 사용되며, 로컬 테스트를 위한 에뮬레이터 모음, 사용자 데이터를 추적하는 인증, Cloud Functions를 기반으로 데이터와 미디어를 유지하는 Firestore 및 Storage, 마지막으로 앱을 배포하는 Firebase 호스팅이 사용됩니다.
학습할 내용
- 에뮬레이터 도구 모음을 사용하여 로컬에서 Firebase 제품으로 개발하는 방법
- AngularFire로 웹 앱을 개선하는 방법
- Firestore에서 데이터를 유지하는 방법
- Storage에 미디어를 유지하는 방법
- Firebase 호스팅에 앱을 배포하는 방법
- Cloud Functions를 사용하여 데이터베이스 및 API와 상호작용하는 방법
필요한 사항
- Node.js 버전 10 이상
- Firebase 프로젝트를 만들고 관리하기 위한 Google 계정
- Firebase CLI 버전 11.14.2 이상
- 원하는 브라우저(예: Chrome)
- Angular 및 JavaScript에 관한 기본 이해
2. 샘플 코드 가져오기
명령줄에서 Codelab의 GitHub 저장소를 클론합니다.
git clone https://github.com/firebase/codelab-friendlychat-web
또는 git을 설치하지 않은 경우 저장소를 ZIP 파일로 다운로드할 수 있습니다.
GitHub 저장소에는 여러 플랫폼용 샘플 프로젝트가 있습니다.
이 Codelab에서는 다음과 같이 웹 프레임워크 저장소만 사용합니다.
- 📁 webframework: 이 Codelab에서 빌드할 시작 코드입니다.
종속 항목 설치
클론 후 웹 앱을 빌드하기 전에 루트 및 functions
폴더에 종속 항목을 설치합니다.
cd webframework && npm install
cd functions && npm install
Firebase CLI 설치
터미널에서 다음 명령어를 사용하여 Firebase CLI를 설치합니다.
npm install -g firebase-tools
다음을 사용하여 Firebase CLI 버전이 11.14.2 이상인지 다시 확인합니다.
firebase --version
버전이 11.14.2 미만인 경우 다음을 사용하여 업데이트하시기 바랍니다.
npm update firebase-tools
3. Firebase 프로젝트 만들기 및 설정
Firebase 프로젝트 만들기
- Firebase에 로그인합니다.
- Firebase Console에서 프로젝트 추가를 클릭한 후 Firebase 프로젝트의 이름을 <your-project>로 지정합니다. Firebase 프로젝트의 프로젝트 ID를 기억합니다.
- 프로젝트 만들기를 클릭합니다.
중요: Firebase 프로젝트의 이름은 <your-project>이지만, Firebase에서 자동으로 <your-project>-1234 형식으로 고유한 프로젝트 ID를 할당합니다. 이 고유 식별자는 프로젝트가 실제로 식별되는 방식 (CLI에서도 포함)이지만, <your-project>는 단순히 표시 이름입니다.
빌드할 애플리케이션은 웹 앱에 사용할 수 있는 Firebase 제품을 사용합니다.
- Firebase 인증 - 사용자가 앱에 간편하게 로그인할 수 있음
- Cloud Firestore: 클라우드에 구조화된 데이터를 저장하고 데이터가 변경되면 인스턴트 알림을 받을 수 있습니다.
- Firebase용 Cloud Storage: 클라우드에 파일 저장
- Firebase 호스팅 - 애셋을 호스팅하고 제공할 수 있음
- 내부 및 외부 API와 상호작용하는 함수
이러한 제품 중 일부는 특수 구성이 필요하거나 Firebase Console을 사용하여 사용 설정해야 합니다.
프로젝트에 Firebase 웹 앱 추가
- 웹 아이콘을 클릭하여 새 Firebase 웹 앱을 만듭니다.
- 다음 단계에서는 구성 객체가 표시됩니다. 이 객체의 콘텐츠를
environments/environment.ts
파일에 복사합니다.
Firebase 인증에 Google 로그인 사용 설정
사용자가 Google 계정으로 웹 앱에 로그인할 수 있도록 Google에서는 Google 로그인 방법을 사용합니다.
Google 로그인을 사용 설정하려면 다음 안내를 따르세요.
- Firebase Console의 왼쪽 패널에서 빌드 섹션을 찾습니다.
- 인증을 클릭한 후 로그인 방법 탭을 클릭합니다(또는 여기를 클릭하여 로그인 방법 탭으로 바로 이동).
- Google 로그인 제공업체를 사용 설정한 다음 저장을 클릭합니다.
- 앱의 공개용 이름을 <your-project-name>로 설정하고 드롭다운 메뉴에서 프로젝트 지원 이메일을 선택합니다.
Cloud Firestore 사용 설정
- Firebase Console의 빌드 섹션에서 Firestore 데이터베이스를 클릭합니다.
- Cloud Firestore 창에서 데이터베이스 만들기를 클릭합니다.
- Cloud Firestore 데이터가 저장되는 위치를 설정합니다. 기본값으로 두거나 가까운 리전을 선택할 수 있습니다.
Cloud Storage 사용 설정
웹 앱은 Firebase용 Cloud Storage를 사용하여 사진을 저장, 업로드, 공유합니다.
- Firebase Console의 빌드 섹션에서 Storage를 클릭합니다.
- 시작하기 버튼이 없으면 Cloud Storage가 이미
아래의 단계를 따르지 않아도 됩니다.
- 시작하기를 클릭합니다.
- Firebase 프로젝트의 보안 규칙에 대한 면책 조항을 읽은 후 다음을 클릭합니다.
- Cloud Storage 위치에는 Cloud Firestore 데이터베이스에 대해 선택한 것과 동일한 리전이 미리 선택됩니다. 완료를 클릭하여 설정을 완료합니다.
기본 보안 규칙을 사용하면 인증된 모든 사용자가 Cloud Storage에 무엇이든 쓸 수 있습니다. 이 Codelab의 후반부에서 저장소의 보안을 강화합니다.
4. Firebase 프로젝트에 연결
Firebase 명령줄 인터페이스 (CLI)를 사용하면 Firebase 호스팅을 사용하여 웹 앱을 로컬에서 제공하고 Firebase 프로젝트에 웹 앱을 배포할 수 있습니다.
명령줄에서 앱의 로컬 webframework
디렉터리에 액세스할 수 있는지 확인합니다.
Firebase 프로젝트에 웹 앱 코드를 연결합니다. 먼저 명령줄에서 Firebase CLI에 로그인합니다.
firebase login
그런 다음 다음 명령어를 실행하여 프로젝트 별칭을 만듭니다. $YOUR_PROJECT_ID
를 Firebase 프로젝트의 ID로 바꿉니다.
firebase use $YOUR_PROJECT_ID
AngularFire 추가
앱에 AngularFire를 추가하려면 다음 명령어를 실행합니다.
ng add @angular/fire
그런 다음 명령줄 안내에 따라 Firebase 프로젝트에 있는 기능을 선택합니다.
Firebase 초기화
Firebase 프로젝트를 초기화하려면 다음을 실행합니다.
firebase init
그런 다음 명령줄 메시지에 따라 Firebase 프로젝트에 사용된 기능과 에뮬레이터를 선택합니다.
에뮬레이터 시작
webframework
디렉터리에서 다음 명령어를 실행하여 에뮬레이터를 시작합니다.
firebase emulators:start
최종적으로 다음과 같은 내용이 표시됩니다.
$ firebase emulators:start
i emulators: Starting emulators: auth, functions, firestore, hosting, functions
i firestore: Firestore Emulator logging to firestore-debug.log
i hosting: Serving hosting files from: public
✔ hosting: Local server: http://localhost:5000
i ui: Emulator UI logging to ui-debug.log
i functions: Watching "/functions" for Cloud Functions...
✔ functions[updateMap]: firestore function initialized.
┌─────────────────────────────────────────────────────────────┐
│ ✔ All emulators ready! It is now safe to connect your app. │
│ i View Emulator UI at http://localhost:4000 │
└─────────────────────────────────────────────────────────────┘
┌────────────────┬────────────────┬─────────────────────────────────┐
│ Emulator │ Host:Port │ View in Emulator UI │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Authentication │ localhost:9099 │ http://localhost:4000/auth │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Functions │ localhost:5001 │ http://localhost:4000/functions │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Firestore │ localhost:8080 │ http://localhost:4000/firestore │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Hosting │ localhost:5000 │ n/a │
└────────────────┴────────────────┴─────────────────────────────────┘
Emulator Hub running at localhost:4400
Other reserved ports: 4500
Issues? Report them at https://github.com/firebase/firebase-tools/issues and attach the *-debug.log files.
✔All emulators ready!
메시지가 표시되면 에뮬레이터를 사용할 수 있습니다.
아직 작동하지 않는 여행 앱의 UI가 표시됩니다.
이제 빌드를 시작해 보겠습니다.
5. 에뮬레이터에 웹 앱 연결
에뮬레이터 로그의 표에 따르면 Cloud Firestore 에뮬레이터는 포트 8080에서 리슨하고 인증 에뮬레이터는 포트 9099에서 리슨합니다.
EmulatorUI 열기
웹브라우저에서 http://127.0.0.1:4000/으로 이동합니다. 에뮬레이터 도구 모음 UI가 표시됩니다.
에뮬레이터를 사용하도록 앱 라우팅
src/app/app.module.ts
에서 다음 코드를 AppModule
의 가져오기 목록에 추가합니다.
@NgModule({
declarations: [...],
imports: [
provideFirebaseApp(() => initializeApp(environment.firebase)),
provideAuth(() => {
const auth = getAuth();
if (location.hostname === 'localhost') {
connectAuthEmulator(auth, 'http://127.0.0.1:9099', { disableWarnings: true });
}
return auth;
}),
provideFirestore(() => {
const firestore = getFirestore();
if (location.hostname === 'localhost') {
connectFirestoreEmulator(firestore, '127.0.0.1', 8080);
}
return firestore;
}),
provideFunctions(() => {
const functions = getFunctions();
if (location.hostname === 'localhost') {
connectFunctionsEmulator(functions, '127.0.0.1', 5001);
}
return functions;
}),
provideStorage(() => {
const storage = getStorage();
if (location.hostname === 'localhost') {
connectStorageEmulator(storage, '127.0.0.1', 5001);
}
return storage;
}),
...
]
이제 앱이 로컬 에뮬레이터를 사용하도록 구성되었으므로 테스트와 개발을 로컬에서 실행할 수 있습니다.
6. 인증 추가
이제 앱에 에뮬레이터가 설정되었으므로 각 사용자가 메시지를 게시하기 전에 로그인하도록 인증 기능을 추가할 수 있습니다.
이렇게 하려면 AngularFire에서 직접 signin
함수를 가져오고 authState
함수로 사용자의 인증 상태를 추적하면 됩니다. 로드 시 페이지에서 사용자 인증 상태를 확인하도록 로그인 페이지 함수를 수정합니다.
AngularFire 인증 삽입
src/app/pages/login-page/login-page.component.ts
의 @angular/fire/auth
에서 Auth
를 가져와 LoginPageComponent
에 삽입합니다. Google과 같은 인증 제공업체와 signin
, signout
와 같은 함수도 동일한 패키지에서 직접 가져와 앱에서 사용할 수 있습니다.
import { Auth, GoogleAuthProvider, signInWithPopup, signOut, user } from '@angular/fire/auth';
export class LoginPageComponent implements OnInit {
private auth: Auth = inject(Auth);
private provider = new GoogleAuthProvider();
user$ = user(this.auth);
constructor() {}
ngOnInit(): void {}
login() {
signInWithPopup(this.auth, this.provider).then((result) => {
const credential = GoogleAuthProvider.credentialFromResult(result);
return credential;
})
}
logout() {
signOut(this.auth).then(() => {
console.log('signed out');}).catch((error) => {
console.log('sign out error: ' + error);
})
}
}
이제 로그인 페이지가 작동합니다. 로그인해 보고 인증 에뮬레이터에서 결과를 확인합니다.
7. Firestore 구성하기
이 단계에서는 Firestore에 저장된 여행 블로그 게시물을 게시하고 업데이트하는 기능을 추가합니다.
인증과 마찬가지로 Firestore 함수는 AngularFire에서 사전 패키징되어 제공됩니다. 각 문서는 컬렉션에 속하며 각 문서는 중첩된 컬렉션을 가질 수도 있습니다. 여행 블로그 게시물을 만들고 업데이트하려면 Firestore에서 문서의 path
를 알아야 합니다.
TravelService 구현
웹 앱에서 여러 페이지가 Firestore 문서를 읽고 업데이트해야 하므로 src/app/services/travel.service.ts
에서 함수를 구현하여 페이지마다 동일한 AngularFire 함수를 반복적으로 삽입하지 않을 수 있습니다.
먼저 이전 단계와 유사한 Auth
와 Firestore
를 서비스에 삽입합니다. 현재 인증 상태를 수신 대기하는 관찰 가능한 user$
객체를 정의하는 것도 유용합니다.
import { doc, docData, DocumentReference, Firestore, getDoc, setDoc, updateDoc, collection, addDoc, deleteDoc, collectionData, Timestamp } from "@angular/fire/firestore";
export class TravelService {
firestore: Firestore = inject(Firestore);
auth: Auth = inject(Auth);
user$ = authState(this.auth).pipe(filter(user => user !== null), map(user => user!));
router: Router = inject(Router);
여행 게시물 추가
여행 게시물은 Firestore에 저장된 문서로 존재하며, 문서는 컬렉션 내에 있어야 하므로 모든 여행 게시물이 포함된 컬렉션의 이름은 travels
입니다. 따라서 여행 게시물의 경로는 travels/
가 됩니다.
AngularFire의 addDoc
함수를 사용하면 객체를 컬렉션에 삽입할 수 있습니다.
async addEmptyTravel(userId: String) {
...
addDoc(collection(this.firestore, 'travels'), travelData).then((travelRef) => {
collection(this.firestore, `travels/${travelRef.id}/stops`);
setDoc(travelRef, {... travelData, id: travelRef.id})
this.router.navigate(['edit', `${travelRef.id}`]);
return travelRef;
})
}
데이터 업데이트 및 삭제
여행 게시물의 UID를 통해 Firestore에 저장된 문서의 경로를 추론할 수 있습니다. 그런 다음 AngularFire의 updateFoc
및 deleteDoc
함수를 사용하여 문서를 읽거나 업데이트하거나 삭제할 수 있습니다.
async updateData(path: string, data: Partial<Travel | Stop>) {
await updateDoc(doc(this.firestore, path), data)
}
async deleteData(path: string) {
const ref = doc(this.firestore, path);
await deleteDoc(ref)
}
관찰 가능한 것으로 데이터 읽기
그 과정에서 이동 게시물과 정류장은 생성 후 수정할 수 있으므로 문서 객체를 observable로 가져와서 모든 변경사항을 구독하는 것이 더 유용할 수 있습니다. 이 기능은 @angular/fire/firestore
의 docData
및 collectionData
함수에서 제공합니다.
getDocData(path: string) {
return docData(doc(this.firestore, path), {idField: 'id'}) as Observable<Travel | Stop>
}
getCollectionData(path: string) {
return collectionData(collection(this.firestore, path), {idField: 'id'}) as Observable<Travel[] | Stop[]>
}
여행 게시물에 경유지 추가하기
이동 후 작업이 설정되었으므로 이제 정류장을 고려할 차례입니다. 정류장은 다음과 같이 여행 게시물의 하위 컬렉션 아래에 있습니다. travels/
이는 여행 게시물을 만드는 것과 거의 동일하므로 직접 구현해 보거나 아래에서 구현을 확인하세요.
async addStop(travelId: string) {
...
const ref = await addDoc(collection(this.firestore, `travels/${travelId}/stops`), stopData)
setDoc(ref, {...stopData, id: ref.id})
}
좋은 소식입니다. Firestore 함수가 여행 서비스에 구현되었으므로 이제 실제로 작동하는 것을 확인할 수 있습니다.
앱에서 Firestore 함수 사용
src/app/pages/my-travels/my-travels.component.ts
로 이동하고 TravelService
를 삽입하여 함수를 사용합니다.
travelService = inject(TravelService);
travelsData$: Observable<Travel[]>;
stopsList$!: Observable<Stop[]>;
constructor() {
this.travelsData$ = this.travelService.getCollectionData(`travels`) as Observable<Travel[]>
}
TravelService
는 생성자에서 호출되어 모든 이동의 Observable 배열을 가져옵니다.
현재 사용자의 여행만 필요한 경우에는 query
함수를 사용합니다.
보안을 보장하는 다른 방법으로는 보안 규칙 구현 또는 아래 선택적 단계에서 살펴본 Firestore와 함께 Cloud Functions를 사용하는 방법 등이 있습니다.
그런 다음 TravelService
에 구현된 함수를 호출하기만 하면 됩니다.
async createTravel(userId: String) {
this.travelService.addEmptyTravel(userId);
}
deleteTravel(travelId: String) {
this.travelService.deleteData(`travels/${travelId}`)
}
이제 My Travels 페이지가 작동할 것입니다. 새 여행 게시물을 만들면 Firestore 에뮬레이터에서 어떤 일이 발생하는지 확인하세요.
그런 다음 /src/app/pages/edit-travels/edit-travels.component.ts
의 업데이트 함수를 반복합니다.
travelService: TravelService = inject(TravelService)
travelId = this.activatedRoute.snapshot.paramMap.get('travelId');
travelData$: Observable<Travel>;
stopsData$: Observable<Stop[]>;
constructor() {
this.travelData$ = this.travelService.getDocData(`travels/${this.travelId}`) as Observable<Travel>
this.stopsData$ = this.travelService.getCollectionData(`travels/${this.travelId}/stops`) as Observable<Stop[]>
}
updateCurrentTravel(travel: Partial<Travel>) {
this.travelService.updateData(`travels${this.travelId}`, travel)
}
updateCurrentStop(stop: Partial<Stop>) {
stop.type = stop.type?.toString();
this.travelService.updateData(`travels${this.travelId}/stops/${stop.id}`, stop)
}
addStop() {
if (!this.travelId) return;
this.travelService.addStop(this.travelId);
}
deleteStop(stopId: string) {
if (!this.travelId || !stopId) {
return;
}
this.travelService.deleteData(`travels${this.travelId}/stops/${stopId}`)
this.stopsData$ = this.travelService.getCollectionData(`travels${this.travelId}/stops`) as Observable<Stop[]>
}
8. 스토리지 구성
이제 저장소를 구현하여 이미지 및 기타 유형의 미디어를 저장합니다.
Cloud Firestore는 JSON 객체와 같은 구조화된 데이터를 저장하는 데 가장 적합합니다. Cloud Storage는 파일 또는 blob을 저장하도록 설계되었습니다. 이 앱에서 사용자가 여행 사진을 공유하도록 허용하는 데 사용합니다.
Firestore와 마찬가지로 Storage를 사용하여 파일을 저장하고 업데이트하려면 각 파일의 고유 식별자가 필요합니다.
TraveService
에서 함수를 구현해 보겠습니다.
파일 업로드
src/app/services/travel.service.ts
로 이동하여 AngularFire에서 Storage를 삽입합니다.
export class TravelService {
firestore: Firestore = inject(Firestore);
auth: Auth = inject(Auth);
storage: Storage = inject(Storage);
업로드 함수를 구현합니다.
async uploadToStorage(path: string, input: HTMLInputElement, contentType: any) {
if (!input.files) return null
const files: FileList = input.files;
for (let i = 0; i < files.length; i++) {
const file = files.item(i);
if (file) {
const imagePath = `${path}/${file.name}`
const storageRef = ref(this.storage, imagePath);
await uploadBytesResumable(storageRef, file, contentType);
return await getDownloadURL(storageRef);
}
}
return null;
}
Firestore의 문서와 Cloud Storage의 파일에 액세스하는 것의 주된 차이점은 두 파일 모두 구조화된 폴더 경로를 따르지만 getDownloadURL
를 통해 기본 URL과 경로 조합을 가져온 다음 파일에 저장하고 사용할 수 있다는 점입니다.
앱에서 함수 사용
src/app/components/edit-stop/edit-stop.component.ts
로 이동하고 다음을 사용하여 업로드 함수를 호출합니다.
async uploadFile(file: HTMLInputElement, stop: Partial<Stop>) {
const path = `/travels/${this.travelId}/stops/${stop.id}`
const url = await this.travelService.uploadToStorage(path, file, {contentType: 'image/png'});
stop.image = url ? url : '';
this.travelService.updateData(path, stop);
}
이미지가 업로드되면 미디어 파일 자체가 저장소에 업로드되고 URL이 Firestore의 문서에 저장됩니다.
9. 애플리케이션 배포
이제 애플리케이션을 배포할 준비가 되었습니다.
src/environments/environment.ts
에서 src/environments/environment.prod.ts
로 firebase
구성을 복사하고 다음을 실행합니다.
firebase deploy
다음과 같은 결과를 확인할 수 있습니다.
✔ Browser application bundle generation complete.
✔ Copying assets complete.
✔ Index html generation complete.
=== Deploying to 'friendly-travels-b6a4b'...
i deploying storage, firestore, hosting
i firebase.storage: checking storage.rules for compilation errors...
✔ firebase.storage: rules file storage.rules compiled successfully
i firestore: reading indexes from firestore.indexes.json...
i cloud.firestore: checking firestore.rules for compilation errors...
✔ cloud.firestore: rules file firestore.rules compiled successfully
i storage: latest version of storage.rules already up to date, skipping upload...
i firestore: deploying indexes...
i firestore: latest version of firestore.rules already up to date, skipping upload...
✔ firestore: deployed indexes in firestore.indexes.json successfully for (default) database
i hosting[friendly-travels-b6a4b]: beginning deploy...
i hosting[friendly-travels-b6a4b]: found 6 files in .firebase/friendly-travels-b6a4b/hosting
✔ hosting[friendly-travels-b6a4b]: file upload complete
✔ storage: released rules storage.rules to firebase.storage
✔ firestore: released rules firestore.rules to cloud.firestore
i hosting[friendly-travels-b6a4b]: finalizing version...
✔ hosting[friendly-travels-b6a4b]: version finalized
i hosting[friendly-travels-b6a4b]: releasing new version...
✔ hosting[friendly-travels-b6a4b]: release complete
✔ Deploy complete!
Project Console: https://console.firebase.google.com/project/friendly-travels-b6a4b/overview
Hosting URL: https://friendly-travels-b6a4b.web.app
10. 수고하셨습니다.
이제 애플리케이션이 완성되고 Firebase 호스팅에 배포되었습니다. 이제 Firebase Console에서 모든 데이터와 분석에 액세스할 수 있습니다.
AngularFire, Functions, 보안 규칙에 관한 자세한 내용은 아래의 선택적 단계와 다른 Firebase Codelab을 확인하세요.
11. 선택사항: AngularFire 인증 가드
AngularFire는 Firebase 인증과 함께 경로에 대한 인증 기반의 가드도 제공하므로 액세스 권한이 부족한 사용자를 리디렉션할 수 있습니다. 이렇게 하면 보호된 데이터에 액세스하는 사용자로부터 앱을 보호할 수 있습니다.
src/app/app-routing.module.ts
에서 다음을 가져옵니다.
import {AuthGuard, redirectLoggedInTo, redirectUnauthorizedTo} from '@angular/fire/auth-guard'
그런 다음 특정 페이지에서 사용자가 언제, 어디로 리디렉션되어야 하는지와 같은 함수를 정의할 수 있습니다.
const redirectUnauthorizedToLogin = () => redirectUnauthorizedTo(['signin']);
const redirectLoggedInToTravels = () => redirectLoggedInTo(['my-travels']);
그런 다음 경로에 추가하기만 하면 됩니다.
const routes: Routes = [
{path: '', component: LoginPageComponent, canActivate: [AuthGuard], data: {authGuardPipe: redirectLoggedInToTravels}},
{path: 'signin', component: LoginPageComponent, canActivate: [AuthGuard], data: {authGuardPipe: redirectLoggedInToTravels}},
{path: 'my-travels', component: MyTravelsComponent, canActivate: [AuthGuard], data: {authGuardPipe: redirectUnauthorizedToLogin}},
{path: 'edit/:travelId', component: EditTravelsComponent, canActivate: [AuthGuard], data: {authGuardPipe: redirectUnauthorizedToLogin}},
];
12. 선택사항: 보안 규칙
Firestore와 Cloud Storage 모두 보안 규칙(각각 firestore.rules
및 security.rules
)을 사용하여 보안을 적용하고 데이터의 유효성을 검사합니다.
현재 Firestore 및 Storage 데이터는 읽기 및 쓰기에 대해 개방형 액세스 권한을 가지고 있지만 사용자가 게시물 수! 보안 규칙을 사용하여 컬렉션 및 문서에 대한 액세스를 제한할 수 있습니다.
Firestore 규칙
인증된 사용자만 여행 게시물을 볼 수 있도록 하려면 firestore.rules
파일로 이동하여 다음을 추가합니다.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/travels {
allow read: if request.auth.uid != null;
allow write:
if request.auth.uid == request.resource.data.userId;
}
}
보안 규칙을 사용하여 데이터를 검증할 수도 있습니다.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/posts {
allow read: if request.auth.uid != null;
allow write:
if request.auth.uid == request.resource.data.userId;
&& "author" in request.resource.data
&& "text" in request.resource.data
&& "timestamp" in request.resource.data;
}
}
스토리지 규칙
마찬가지로 보안 규칙을 사용하여 storage.rules
의 저장소 데이터베이스에 대한 액세스를 적용할 수 있습니다. 더 복잡한 검사에는 함수를 사용할 수도 있습니다.
rules_version = '2';
function isImageBelowMaxSize(maxSizeMB) {
return request.resource.size < maxSizeMB * 1024 * 1024
&& request.resource.contentType.matches('image/.*');
}
service firebase.storage {
match /b/{bucket}/o {
match /{userId}/{postId}/{filename} {
allow write: if request.auth != null
&& request.auth.uid == userId && isImageBelowMaxSize(5);
allow read;
}
}
}