Лаборатория разработки веб-фреймворков Firebase Angular

1. Что вы создадите

В этой лаборатории кода вы создадите блог о путешествиях с совместной картой в реальном времени с использованием новейшей версии нашей библиотеки Angular: AngularFire . Окончательное веб-приложение будет состоять из блога о путешествиях, куда вы сможете загружать изображения каждого места, куда вы побывали.

AngularFire будет использоваться для создания веб-приложения, Emulator Suite для локального тестирования, аутентификации для отслеживания пользовательских данных, Firestore и Storage для сохранения данных и мультимедиа на базе облачных функций и, наконец, хостинга Firebase для развертывания приложения.

Что вы узнаете

  • Как разрабатывать продукты Firebase локально с помощью Emulator Suite
  • Как улучшить ваше веб-приложение с помощью AngularFire
  • Как сохранить ваши данные в Firestore
  • Как сохранить носитель в хранилище
  • Как развернуть ваше приложение на хостинге Firebase
  • Как использовать облачные функции для взаимодействия с вашими базами данных и API

Что вам понадобится

  • Node.js версии 10 или выше
  • Аккаунт Google для создания и управления вашим проектом Firebase.
  • Firebase CLI версии 11.14.2 или новее.
  • Браузер по вашему выбору, например Chrome.
  • Базовое понимание Angular и Javascript

2. Получите пример кода

Клонируйте репозиторий GitHub codelab из командной строки:

git clone https://github.com/firebase/codelab-friendlychat-web

Альтернативно, если у вас не установлен git, вы можете загрузить репозиторий в виде ZIP-файла .

Репозиторий Github содержит примеры проектов для нескольких платформ.

Эта лаборатория кода использует только репозиторий веб-фреймворка:

  • 📁 webframework : начальный код, который вы будете использовать во время этой лабораторной работы.

Установить зависимости

После клонирования установите зависимости в корневую папку и папку functions , прежде чем создавать веб-приложение.

cd webframework && npm install
cd functions && npm install

Установите интерфейс командной строки Firebase

Установите Firebase CLI, используя эту команду в терминале:

npm install -g firebase-tools

Дважды проверьте, что ваша версия Firebase CLI выше 11.14.2, используя:

firebase  --version

Если ваша версия ниже 11.14.2, обновите, используя:

npm update firebase-tools

3. Создайте и настройте проект Firebase.

Создать проект Firebase

  1. Войдите в Firebase .
  2. В консоли Firebase нажмите «Добавить проект» и назовите свой проект Firebase <your-project> . Запомните идентификатор вашего проекта Firebase.
  3. Нажмите Создать проект .

Важно : ваш проект Firebase будет называться <ваш-проект> , но Firebase автоматически присвоит ему уникальный идентификатор проекта в форме <ваш-проект>-1234 . Этот уникальный идентификатор фактически идентифицирует ваш проект (в том числе в CLI), тогда как <ваш-проект> — это просто отображаемое имя.

Приложение, которое мы собираемся создать, использует продукты Firebase, доступные для веб-приложений:

  • Аутентификация Firebase , позволяющая пользователям легко входить в ваше приложение.
  • Cloud Firestore для сохранения структурированных данных в облаке и мгновенного получения уведомлений при изменении данных.
  • Облачное хранилище для Firebase для сохранения файлов в облаке.
  • Хостинг Firebase для размещения и обслуживания ваших ресурсов.
  • Функции для взаимодействия с внутренними и внешними API.

Некоторые из этих продуктов требуют специальных конфигураций или их необходимо включить с помощью консоли Firebase.

Добавьте веб-приложение Firebase в проект

  1. Нажмите значок веб-сайта, чтобы создать новое веб-приложение Firebase.
  2. На следующем шаге вы увидите объект конфигурации. Скопируйте содержимое этого объекта в файл environments/environment.ts .

Включите вход в Google для аутентификации Firebase

Чтобы пользователи могли входить в веб-приложение со своими учетными записями Google, мы будем использовать метод входа Google .

Чтобы включить вход в Google :

  1. В консоли Firebase найдите раздел «Сборка» на левой панели.
  2. Нажмите «Аутентификация» , затем перейдите на вкладку «Метод входа» (или нажмите здесь, чтобы перейти непосредственно туда).
  3. Включите службу входа в систему Google , затем нажмите «Сохранить» .
  4. Установите общедоступное имя вашего приложения на <имя-вашего-проекта> и выберите адрес электронной почты поддержки проекта из раскрывающегося меню.

Включить Cloud Firestore

  1. В разделе «Сборка » консоли Firebase нажмите «База данных Firestore» .
  2. Нажмите Создать базу данных на панели Cloud Firestore.
  3. Укажите место, где хранятся данные Cloud Firestore. Вы можете оставить это значение по умолчанию или выбрать ближайший к вам регион.

Включить облачное хранилище

Веб-приложение использует Cloud Storage for Firebase для хранения, загрузки и обмена изображениями.

  1. В разделе «Сборка » консоли Firebase нажмите « Хранилище» .
  2. Если кнопки «Начать» нет, это означает, что облачное хранилище уже

включен, и вам не нужно выполнять действия, описанные ниже.

  1. Нажмите «Начать» .
  2. Прочтите заявление об отказе от ответственности о правилах безопасности для вашего проекта Firebase, затем нажмите «Далее» .
  3. Местоположение Cloud Storage предварительно выбирается в том же регионе, который вы выбрали для своей базы данных Cloud Firestore. Нажмите Готово, чтобы завершить настройку.

Благодаря правилам безопасности по умолчанию любой прошедший проверку подлинности пользователь может записывать в Cloud Storage что угодно. Позже в этой лаборатории мы сделаем наше хранилище более безопасным.

4. Подключитесь к своему проекту Firebase.

Интерфейс командной строки (CLI) Firebase позволяет вам использовать хостинг Firebase для локального обслуживания вашего веб-приложения, а также для развертывания вашего веб-приложения в проекте Firebase.

Убедитесь, что ваша командная строка обращается к локальному каталогу webframework вашего приложения.

Подключите код веб-приложения к своему проекту Firebase. Сначала войдите в Firebase CLI в командной строке:

firebase login

Затем выполните следующую команду, чтобы создать псевдоним проекта. Замените $YOUR_PROJECT_ID идентификатором вашего проекта Firebase.

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! сообщение, эмуляторы готовы к использованию.

Вы должны увидеть пользовательский интерфейс вашего приложения для путешествий, который (пока!) не работает:

Теперь приступим к строительству!

5. Подключите веб-приложение к эмуляторам.

Судя по таблице в журналах эмулятора, эмулятор Cloud Firestore прослушивает порт 8080, а эмулятор аутентификации — порт 9099.

Откройте интерфейс эмулятора.

В веб-браузере перейдите по адресу http://127.0.0.1:4000/ . Вы должны увидеть пользовательский интерфейс Emulator Suite.

Направьте приложение на использование эмуляторов

В 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. Добавление аутентификации

Теперь, когда для приложения настроены эмуляторы, мы можем добавить функции аутентификации, чтобы гарантировать, что каждый пользователь войдет в систему, прежде чем публиковать сообщения.

Для этого мы можем импортировать функции signin непосредственно из AngularFire и отслеживать состояние аутентификации вашего пользователя с помощью функции authState . Измените функции страницы входа в систему, чтобы страница проверяла состояние аутентификации пользователя при загрузке.

Внедрение аутентификации AngularFire

В src/app/pages/login-page/login-page.component.ts импортируйте Auth из @angular/fire/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. Каждый документ принадлежит коллекции, и каждый документ также может иметь вложенные коллекции. Для создания и обновления записи в блоге о путешествиях необходимо знать path к документу в Firestore.

Внедрение 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/

Используя функцию addDoc из AngularFire, объект можно вставить в коллекцию:

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)
}

Чтение данных как наблюдаемых

Поскольку путевые записи и остановки по пути можно изменить после создания, было бы полезнее получать объекты документа как наблюдаемые, чтобы подписаться на любые вносимые изменения. Эту функциональность предлагают функции docData и collectionData из @angular/fire/firestore .

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/ /stops/ travels/ /stops/

Это почти идентично созданию поста о путешествиях, поэтому попробуйте реализовать его самостоятельно или посмотрите реализацию ниже:

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, как описано в дополнительных шагах ниже.

Затем просто вызовите функции, реализованные в TravelService .

async  createTravel(userId: String) {
	this.travelService.addEmptyTravel(userId);
}

deleteTravel(travelId: String) {
	this.travelService.deleteData(`travels/${travelId}`)
}

Теперь страница «Мои путешествия» должна работать! Посмотрите, что происходит в вашем эмуляторе 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. Облачное хранилище предназначено для хранения файлов или больших двоичных объектов. В этом приложении вы будете использовать его, чтобы позволить пользователям делиться фотографиями из своих путешествий.

Как и в случае с Firestore, для хранения и обновления файлов с помощью Storage требуется уникальный идентификатор для каждого файла.

Давайте реализуем функции в TraveService :

Загрузка файла

Перейдите в src/app/services/travel.service.ts и добавьте Storage из AngularFire:

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 заключается в том, что, хотя они оба следуют путям, структурированным по папкам, базовый URL-адрес и комбинация путей получаются через getDownloadURL , который затем можно сохранить и использовать в файл.

Использование функции в приложении

Перейдите в 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. Развертывание приложения

Теперь мы готовы развернуть приложение!

Скопируйте конфигурации firebase из src/environments/environment.ts в src/environments/environment.prod.ts и запустите:

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.

Чтобы узнать больше о AngularFire, функциях и правилах безопасности, не забудьте ознакомиться с дополнительными шагами ниже, а также с другими лабораториями Firebase Codelab !

11. Необязательно: защита аутентификации AngularFire.

Наряду с аутентификацией Firebase, AngularFire также предлагает защиту маршрутов на основе аутентификации, так что пользователи с недостаточным доступом могут быть перенаправлены. Это помогает защитить приложение от доступа пользователей к защищенным данным.

В 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.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;
		}
	}
}
,

1. Что вы создадите

В этой лаборатории кода вы создадите блог о путешествиях с совместной картой в реальном времени с использованием новейшей версии нашей библиотеки Angular: AngularFire . Окончательное веб-приложение будет представлять собой блог о путешествиях, куда вы сможете загружать изображения каждого места, куда вы побывали.

AngularFire будет использоваться для создания веб-приложения, Emulator Suite для локального тестирования, аутентификации для отслеживания пользовательских данных, Firestore и Storage для сохранения данных и мультимедиа на базе облачных функций и, наконец, хостинга Firebase для развертывания приложения.

Что вы узнаете

  • Как разрабатывать продукты Firebase локально с помощью Emulator Suite
  • Как улучшить ваше веб-приложение с помощью AngularFire
  • Как сохранить ваши данные в Firestore
  • Как сохранить носитель в хранилище
  • Как развернуть ваше приложение на хостинге Firebase
  • Как использовать облачные функции для взаимодействия с вашими базами данных и API

Что вам понадобится

  • Node.js версии 10 или выше
  • Аккаунт Google для создания и управления вашим проектом Firebase.
  • Firebase CLI версии 11.14.2 или новее.
  • Браузер по вашему выбору, например Chrome.
  • Базовое понимание Angular и Javascript

2. Получите пример кода

Клонируйте репозиторий GitHub codelab из командной строки:

git clone https://github.com/firebase/codelab-friendlychat-web

Альтернативно, если у вас не установлен git, вы можете загрузить репозиторий в виде ZIP-файла .

Репозиторий Github содержит примеры проектов для нескольких платформ.

Эта лаборатория кода использует только репозиторий веб-фреймворка:

  • 📁 webframework : начальный код, который вы будете использовать во время этой лабораторной работы.

Установить зависимости

После клонирования установите зависимости в корневую папку и папку functions , прежде чем создавать веб-приложение.

cd webframework && npm install
cd functions && npm install

Установите интерфейс командной строки Firebase

Установите Firebase CLI, используя эту команду в терминале:

npm install -g firebase-tools

Дважды проверьте, что ваша версия Firebase CLI выше 11.14.2, используя:

firebase  --version

Если ваша версия ниже 11.14.2, обновите, используя:

npm update firebase-tools

3. Создайте и настройте проект Firebase.

Создать проект Firebase

  1. Войдите в Firebase .
  2. В консоли Firebase нажмите «Добавить проект» и назовите свой проект Firebase <your-project> . Запомните идентификатор вашего проекта Firebase.
  3. Нажмите Создать проект .

Важно : ваш проект Firebase будет называться <your-project> , но Firebase автоматически присвоит ему уникальный идентификатор проекта в форме <your-project>-1234 . Этот уникальный идентификатор фактически идентифицирует ваш проект (в том числе в CLI), тогда как <ваш-проект> — это просто отображаемое имя.

Приложение, которое мы собираемся создать, использует продукты Firebase, доступные для веб-приложений:

  • Аутентификация Firebase , позволяющая пользователям легко входить в ваше приложение.
  • Cloud Firestore для сохранения структурированных данных в облаке и мгновенного получения уведомлений при изменении данных.
  • Облачное хранилище для Firebase для сохранения файлов в облаке.
  • Хостинг Firebase для размещения и обслуживания ваших ресурсов.
  • Функции для взаимодействия с внутренними и внешними API.

Некоторые из этих продуктов требуют специальных конфигураций или их необходимо включить с помощью консоли Firebase.

Добавьте веб-приложение Firebase в проект

  1. Нажмите значок веб-сайта, чтобы создать новое веб-приложение Firebase.
  2. На следующем шаге вы увидите объект конфигурации. Скопируйте содержимое этого объекта в файл environments/environment.ts .

Включите вход в Google для аутентификации Firebase

Чтобы пользователи могли входить в веб-приложение со своими учетными записями Google, мы будем использовать метод входа Google .

Чтобы включить вход в Google :

  1. В консоли Firebase найдите раздел «Сборка» на левой панели.
  2. Нажмите «Аутентификация» , затем перейдите на вкладку «Метод входа» (или нажмите здесь, чтобы перейти непосредственно туда).
  3. Включите службу входа в систему Google , затем нажмите «Сохранить» .
  4. Установите общедоступное имя вашего приложения на <имя-вашего-проекта> и выберите адрес электронной почты поддержки проекта из раскрывающегося меню.

Включить Cloud Firestore

  1. В разделе «Сборка » консоли Firebase нажмите «База данных Firestore» .
  2. Нажмите Создать базу данных на панели Cloud Firestore.
  3. Укажите место, где хранятся данные Cloud Firestore. Вы можете оставить это значение по умолчанию или выбрать ближайший к вам регион.

Включить облачное хранилище

Веб-приложение использует Cloud Storage for Firebase для хранения, загрузки и обмена изображениями.

  1. В разделе «Сборка » консоли Firebase нажмите « Хранилище» .
  2. Если кнопки «Начать» нет, это означает, что облачное хранилище уже

включен, и вам не нужно выполнять действия, описанные ниже.

  1. Нажмите «Начать» .
  2. Прочтите заявление об отказе от ответственности о правилах безопасности для вашего проекта Firebase, затем нажмите «Далее» .
  3. Местоположение Cloud Storage предварительно выбирается в том же регионе, который вы выбрали для своей базы данных Cloud Firestore. Нажмите Готово, чтобы завершить настройку.

Благодаря правилам безопасности по умолчанию любой прошедший проверку подлинности пользователь может записывать в Cloud Storage что угодно. Позже в этой лаборатории мы сделаем наше хранилище более безопасным.

4. Подключитесь к своему проекту Firebase.

Интерфейс командной строки (CLI) Firebase позволяет вам использовать хостинг Firebase для локального обслуживания вашего веб-приложения, а также для развертывания вашего веб-приложения в проекте Firebase.

Убедитесь, что ваша командная строка обращается к локальному каталогу webframework вашего приложения.

Подключите код веб-приложения к своему проекту Firebase. Сначала войдите в Firebase CLI в командной строке:

firebase login

Затем выполните следующую команду, чтобы создать псевдоним проекта. Замените $YOUR_PROJECT_ID идентификатором вашего проекта Firebase.

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! сообщение, эмуляторы готовы к использованию.

Вы должны увидеть пользовательский интерфейс вашего приложения для путешествий, который (пока!) не работает:

Теперь приступим к строительству!

5. Подключите веб-приложение к эмуляторам.

Судя по таблице в журналах эмулятора, эмулятор Cloud Firestore прослушивает порт 8080, а эмулятор аутентификации — порт 9099.

Откройте интерфейс эмулятора.

В веб-браузере перейдите по адресу http://127.0.0.1:4000/ . Вы должны увидеть пользовательский интерфейс Emulator Suite.

Направьте приложение на использование эмуляторов

В 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. Добавление аутентификации

Теперь, когда для приложения настроены эмуляторы, мы можем добавить функции аутентификации, чтобы гарантировать, что каждый пользователь войдет в систему, прежде чем публиковать сообщения.

Для этого мы можем импортировать функции signin непосредственно из AngularFire и отслеживать состояние аутентификации вашего пользователя с помощью функции authState . Измените функции страницы входа так, чтобы страница проверяла состояние аутентификации пользователя при загрузке.

Внедрение аутентификации AngularFire

В src/app/pages/login-page/login-page.component.ts импортируйте Auth из @angular/fire/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. Каждый документ принадлежит коллекции, и каждый документ также может иметь вложенные коллекции. Для создания и обновления записи в блоге о путешествиях необходимо знать path к документу в Firestore.

Внедрение 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/

Используя функцию addDoc из AngularFire, объект можно вставить в коллекцию:

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)
}

Чтение данных как наблюдаемых

Поскольку путевые записи и остановки по пути можно изменить после создания, было бы полезнее получать объекты документа как наблюдаемые, чтобы подписаться на любые вносимые изменения. Эту функциональность предлагают функции docData и collectionData из @angular/fire/firestore .

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/ /stops/ travels/ /stops/

Это почти идентично созданию поста о путешествиях, поэтому попробуйте реализовать его самостоятельно или посмотрите реализацию ниже:

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, как описано в дополнительных шагах ниже.

Затем просто вызовите функции, реализованные в TravelService .

async  createTravel(userId: String) {
	this.travelService.addEmptyTravel(userId);
}

deleteTravel(travelId: String) {
	this.travelService.deleteData(`travels/${travelId}`)
}

Теперь страница «Мои путешествия» должна работать! Посмотрите, что происходит в вашем эмуляторе 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. Облачное хранилище предназначено для хранения файлов или больших двоичных объектов. В этом приложении вы будете использовать его, чтобы позволить пользователям делиться фотографиями из своих путешествий.

Как и в случае с Firestore, для хранения и обновления файлов с помощью Storage требуется уникальный идентификатор для каждого файла.

Давайте реализуем функции в TraveService :

Загрузка файла

Перейдите в src/app/services/travel.service.ts и добавьте Storage из AngularFire:

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 заключается в том, что, хотя они оба следуют путям, структурированным по папкам, базовый URL-адрес и комбинация путей получаются через getDownloadURL , который затем можно сохранить и использовать в файл.

Использование функции в приложении

Перейдите в 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. Развертывание приложения

Теперь мы готовы развернуть приложение!

Скопируйте конфигурации firebase из src/environments/environment.ts в src/environments/environment.prod.ts и запустите:

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.

Чтобы узнать больше о AngularFire, функциях и правилах безопасности, не забудьте ознакомиться с дополнительными шагами ниже, а также с другими лабораториями Firebase Codelab !

11. Необязательно: защита аутентификации AngularFire.

Наряду с аутентификацией Firebase, AngularFire также предлагает защиту маршрутов на основе аутентификации, так что пользователи с недостаточным доступом могут быть перенаправлены. Это помогает защитить приложение от доступа пользователей к защищенным данным.

В 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.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;
		}
	}
}