1. מה יוצרים?
בקודלאב הזה תלמדו ליצור בלוג נסיעות עם מפה שיתופית בזמן אמת, באמצעות הגרסה העדכנית ביותר של ספריית Angular: AngularFire. אפליקציית האינטרנט הסופית תכלול בלוג בנושא טיולים, שבו תוכלו להעלות תמונות לכל מקום שביקרתם בו.
AngularFire ישמש לפיתוח אפליקציית האינטרנט, חבילת אמולטור לבדיקה מקומית, אימות למעקב אחרי נתוני משתמשים, Firestore ו-Storage כדי לשמור נתונים ומדיה, יופעל על ידי Cloud Functions, ולבסוף, אירוח ב-Firebase לפריסת האפליקציה.
מה תלמדו
- איך לפתח עם מוצרי Firebase באופן מקומי באמצעות חבילת Emulator
- איך לשפר את אפליקציית האינטרנט באמצעות AngularFire
- איך לשמור את הנתונים ב-Firestore
- איך לשמור מדיה באחסון
- איך פורסים את האפליקציה ב-Firebase Hosting
- איך משתמשים ב-Cloud Functions כדי ליצור אינטראקציה עם מסדי הנתונים וממשקי ה-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 מכיל פרויקטים לדוגמה לכמה פלטפורמות.
ה-Codelab הזה משתמש רק במאגר ה-webframework:
- 📁 webframework: הקוד הבסיסי שעליו תבנו במהלך ה-Codelab הזה.
התקנת יחסי תלות
אחרי היצירה באמצעות קלון, מתקינים את יחסי התלות ברמה הבסיסית (root) ובתיקייה functions
לפני שמפתחים את אפליקציית האינטרנט.
cd webframework && npm install
cd functions && npm install
התקנת Firebase CLI
מתקינים את Firebase CLI באמצעות הפקודה הבאה בטרמינל:
npm install -g firebase-tools
מוודאים שגרסת ה-CLI של Firebase גדולה מ-11.14.2 באמצעות:
firebase --version
אם הגרסה שלך נמוכה מ-11.14.2, עליך לעדכן אותה באמצעות:
npm update firebase-tools
3. יצירה והגדרה של פרויקט Firebase
יצירת פרויקט Firebase
- נכנסים ל-Firebase.
- במסוף Firebase, לוחצים על הוספת פרויקט ונותנים את השם <your-project> לפרויקט Firebase. חשוב לזכור את מזהה הפרויקט של פרויקט Firebase.
- לוחצים על Create Project.
חשוב: שם הפרויקט ב-Firebase יהיה <your-project>, אבל מערכת Firebase תקצה לו באופן אוטומטי מזהה פרויקט ייחודי בפורמט <your-project>-1234. המזהה הייחודי הזה הוא האופן שבו הפרויקט מזוהה בפועל (כולל ב-CLI), ואילו <your-project> הוא פשוט שם לתצוגה.
האפליקציה שנשיק עכשיו משתמשת במוצרי Firebase שזמינים לאפליקציות אינטרנט:
- אימות ב-Firebase כדי לאפשר למשתמשים להיכנס בקלות לאפליקציה שלכם.
- Cloud Firestore כדי לשמור נתונים מובְנים בענן ולקבל התראות מיידיות על שינויים בנתונים.
- Cloud Storage for Firebase לשמירת קבצים בענן.
- אירוח ב-Firebase לאירוח ולהצגה של הנכסים שלכם.
- פונקציות לאינטראקציה עם ממשקי API פנימיים וחיצוניים.
לחלק מהמוצרים האלה צריך לקבוע הגדרות מיוחדות או להפעיל אותם באמצעות מסוף Firebase.
הוספת אפליקציית אינטרנט של Firebase לפרויקט
- לוחצים על סמל האינטרנט כדי ליצור אפליקציית אינטרנט חדשה ב-Firebase.
- בשלב הבא יוצג אובייקט של הגדרה. מעתיקים את התוכן של האובייקט הזה לקובץ
environments/environment.ts
.
מפעילים את האפשרות כניסה באמצעות חשבון Google ל-Firebase.
כדי לאפשר למשתמשים להיכנס לאפליקציית האינטרנט באמצעות חשבונות Google שלהם, נשתמש בשיטת הכניסה של Google.
כדי להפעיל כניסה באמצעות חשבון Google:
- במסוף Firebase, מאתרים את הקטע Build בחלונית השמאלית.
- לוחצים על אימות ולאחר מכן לוחצים על הכרטיסייה שיטת כניסה (אפשר גם ללחוץ כאן כדי לעבור ישירות לשם).
- מפעילים את ספק הכניסה של Google ולוחצים על שמירה.
- מגדירים את השם הציבורי של האפליקציה כ-<your-project-name> ובוחרים מהתפריט הנפתח באפשרות Project support email (אימייל תמיכה בפרויקט).
הפעלת Cloud Firestore
- בקטע Build במסוף Firebase, לוחצים על Firestore Database.
- לוחצים על Create dataset בחלונית Cloud Firestore.
- הגדרת המיקום שבו יאוחסנו הנתונים שלכם ב-Cloud Firestore. אפשר להשאיר את האפשרות הזו כברירת המחדל או לבחור אזור קרוב אליכם.
הפעלת Cloud Storage
אפליקציית האינטרנט משתמשת ב-Cloud Storage for Firebase כדי לאחסן, להעלות ולשתף תמונות.
- בקטע Build במסוף Firebase, לוחצים על Storage.
- אם הלחצן תחילת העבודה לא מופיע, סימן ש-Cloud Storage כבר
מופעלת, ואין צורך לבצע את השלבים הבאים.
- לוחצים על Get Started.
- קוראים את כתב הוויתור לגבי כללי האבטחה של הפרויקט ב-Firebase ולוחצים על הבא.
- המיקום של Cloud Storage נבחר מראש באותו אזור שבחרתם למסד הנתונים שלכם ב-Cloud Firestore. לוחצים על Done כדי להשלים את ההגדרה.
לפי כללי האבטחה שמוגדרים כברירת מחדל, כל משתמש מאומת יכול לכתוב כל דבר ב-Cloud Storage. נפח האחסון שלנו יהיה מאובטח יותר בהמשך ב-Codelab הזה.
4. מקשרים את פרויקט Firebase
ממשק שורת הפקודה של Firebase (CLI) מאפשר לכם להשתמש באירוח ב-Firebase כדי לשרת את אפליקציית האינטרנט שלכם באופן מקומי, וגם לפרוס את אפליקציית האינטרנט שלכם לפרויקט Firebase.
חשוב לוודא ששורת הפקודה ניגשת לספריית webframework
המקומית של האפליקציה.
מחברים את הקוד של אפליקציית האינטרנט לפרויקט Firebase. קודם כול, מתחברים ל-CLI של Firebase בשורת הפקודה:
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.
פתיחת EmulatorUI
בדפדפן האינטרנט, עוברים לכתובת 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
ישירות מ-AgularFire ולעקוב אחרי מצב האימות של המשתמש באמצעות הפונקציה authState
. משנים את הפונקציות של דף ההתחברות כך שהדף יבדוק את מצב האימות של המשתמש בזמן הטעינה.
החדרת AngularFire Auth
ב-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 מגיעות מ-AgularFire כחבילה מראש. כל מסמך שייך לאוסף, וכל מסמך יכול לכלול גם אוספים בתצוגת עץ. כדי ליצור ולעדכן פוסט בבלוג בנושא נסיעות, צריך לדעת 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. לאחר מכן אפשר לקרוא, לעדכן או למחוק את המסמך באמצעות הפונקציות updateFoc
ו-deleteDoc
של AngularFire:
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/
התהליך הזה כמעט זהה ליצירת פוסט על טיול, אז אתם יכולים לנסות להטמיע אותו בעצמכם או לעיין בהטמעה שמפורטת בהמשך:
async addStop(travelId: string) {
...
const ref = await addDoc(collection(this.firestore, `travels/${travelId}/stops`), stopData)
setDoc(ref, {...stopData, id: ref.id})
}
מצוין! הפונקציות של Firestore יושמו בשירות Travel, כך שאפשר לראות אותן בפעולה.
שימוש בפונקציות של 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
נקרא ב-constructor כדי לקבל מערך Observable של כל הנסיעות.
במקרה שבו יש צורך רק בנסיעות של המשתמש הנוכחי, אפשר להשתמש בפונקציה query
.
שיטות נוספות לשמירה על האבטחה כוללות הטמעת כללי אבטחה או שימוש ב-Cloud Functions עם 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. Cloud Storage נועד לאחסן קבצים או blobs. באפליקציה הזו, תשתמשו בה כדי לאפשר למשתמשים לשתף את תמונות הנסיעה שלהם.
בדומה ל-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 Hosting. כל הנתונים וניתוח הנתונים יהיו זמינים עכשיו במסוף Firebase.
לתכונות נוספות לגבי AngularFire, פונקציות וכללי אבטחה, אל תשכחו לבדוק את השלבים האופציונליים שבהמשך, וגם את Firebase Codelabs !
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
כדי לאפשר רק למשתמשים מאומתים להציג פוסטים בנושא נסיעות, צריך לעבור לקובץ 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;
}
}
}