1- المحتوى الذي ستنشئه
في هذا الدرس التطبيقي حول الترميز، ستعمل على إنشاء مدونة متنقلة تحتوي على خريطة تعاونية في الوقت الفعلي تحتوي على أحدث إصدار من مكتبة Angular: AngularFire. يتكون تطبيق الويب النهائي من مدونة سفر يمكنك من خلالها تحميل صور لكل موقع سافرت إليه.
سيتم استخدام AngularFire لإنشاء تطبيق الويب، وحزمة Emulator Suite للاختبار المحلي، والمصادقة لتتبُّع بيانات المستخدمين، وFirestore والتخزين للاحتفاظ بالبيانات والوسائط، وذلك من خلال ميزة Cloud Functions. وفي النهاية، سيتم استخدام Firebase Hosting لنشر التطبيق.
المعلومات التي ستطّلع عليها
- كيفية التطوير باستخدام منتجات Firebase على الجهاز باستخدام Emulator Suite
- كيفية تحسين تطبيق الويب باستخدام AngularFire
- كيفية الاحتفاظ ببياناتك في Firestore
- كيفية الاحتفاظ بالوسائط في مساحة التخزين
- طريقة نشر تطبيقك في استضافة Firebase
- كيفية استخدام دوال Cloud للتفاعل مع قواعد البيانات وواجهات برمجة التطبيقات
المتطلبات
- Node.js الإصدار 10 أو أحدث
- حساب Google لإنشاء مشروع Firebase وإدارته
- الإصدار 11.14.2 أو إصدار أحدث من واجهة سطر الأوامر في Firebase
- متصفح من اختيارك، مثل Chrome
- فهم أساسي حول Angular وJavaScript
2- الحصول على الرمز النموذجي
استنسِخ مستودع GitHub في الدرس التطبيقي حول الترميز من سطر الأوامر:
git clone https://github.com/firebase/codelab-friendlychat-web
يمكنك بدلاً من ذلك تنزيل المستودع كملف ZIP إذا لم يكن git مثبّتًا لديك.
يحتوي مستودع جيت هب على نماذج مشروعات لأنظمة أساسية متعددة.
لا يستخدم هذا الدرس التطبيقي إلا مستودع إطار الويب:
- 📁 إطار الويب: رمز البدء الذي ستعتمد عليه خلال هذا الدرس التطبيقي حول الترميز.
تثبيت الملحقات
بعد النسخ، ثبِّت الاعتماديات في الجذر والمجلد functions
قبل إنشاء تطبيق الويب.
cd webframework && npm install
cd functions && npm install
تثبيت واجهة سطر الأوامر بنظام Firebase
ثبِّت واجهة سطر الأوامر في Firebase باستخدام الأمر التالي في وحدة طرفية:
npm install -g firebase-tools
يُرجى التحقّق من أنّ إصدار واجهة سطر الأوامر في Firebase أكبر من 11.14.2 باستخدام:
firebase --version
إذا كان الإصدار أقدم من 11.14.2، يُرجى التحديث باستخدام:
npm update firebase-tools
3- إنشاء مشروع على Firebase وإعداده
إنشاء مشروع على Firebase
- سجِّل الدخول إلى Firebase.
- في "وحدة تحكُّم Firebase"، انقر على إضافة مشروع، ثم أدخِل اسمًا لمشروع Firebase <your-project>. تذكّر رقم تعريف مشروعك على Firebase.
- انقر على إنشاء مشروع.
ملاحظة مهمّة: ستتم تسمية مشروعك في Firebase باسم <your-project>، ولكن سيحدّد له Firebase رقم تعريف مشروع فريد تلقائيًا بالتنسيق <your-project>-1234. هذا المعرّف الفريد هو كيفية تحديد مشروعك فعليًا (بما في ذلك واجهة سطر الأوامر)، في حين أن <your-project> هو مجرد اسم معروض.
يستخدم التطبيق الذي سننشئه منتجات Firebase المتاحة لتطبيقات الويب:
- مصادقة Firebase للسماح للمستخدمين بتسجيل الدخول إلى تطبيقك بسهولة
- Cloud Firestore لحفظ البيانات المنظَّمة على السحابة الإلكترونية وتلقّي إشعارات فورية عند تغيير البيانات.
- Cloud Storage for Firebase لحفظ الملفات في السحابة الإلكترونية.
- استضافة Firebase لاستضافة مواد العرض وعرضها.
- الدوال للتفاعل مع واجهات برمجة التطبيقات الداخلية والخارجية.
يجب تفعيل إعدادات خاصة لبعض هذه المنتجات أو تفعيلها باستخدام "وحدة تحكُّم Firebase".
إضافة تطبيق ويب Firebase إلى المشروع
- انقر على رمز الويب لإنشاء تطبيق ويب جديد على Firebase.
- في الخطوة التالية، سيظهر لك كائن ضبط. انسخ محتوى هذا العنصر إلى ملف
environments/environment.ts
.
تفعيل تسجيل الدخول إلى حساب Google لمصادقة Firebase
للسماح للمستخدمين بتسجيل الدخول إلى تطبيق الويب باستخدام حساباتهم على Google، سنستخدم طريقة تسجيل الدخول من Google.
لتفعيل تسجيل الدخول باستخدام Google:
- في وحدة تحكُّم Firebase، ابحث عن قسم إنشاء في اللوحة اليمنى.
- انقر على المصادقة، ثم انقر على علامة التبويب طريقة تسجيل الدخول (أو انقر هنا للانتقال إلى هناك مباشرةً).
- فعِّل مقدِّم خدمة تسجيل الدخول إلى Google، ثم انقر على حفظ.
- اضبط الاسم العلني لتطبيقك على <your-project-name> واختَر بريد إلكتروني لدعم المشروع من القائمة المنسدلة.
تفعيل Cloud Firestore
- في قسم إنشاء في وحدة تحكُّم Firebase، انقر على قاعدة بيانات Firestore.
- انقر على إنشاء قاعدة بيانات في لوحة Cloud Firestore.
- يمكنك ضبط الموقع الجغرافي الذي يتم فيه تخزين بيانات Cloud Firestore. يمكنك ترك هذا الخيار كإعداد تلقائي أو اختيار منطقة قريبة منك.
تفعيل Cloud Storage
يستخدم تطبيق الويب Cloud Storage for Firebase لتخزين الصور وتحميلها ومشاركتها.
- في قسم إنشاء ضمن "وحدة تحكُّم Firebase"، انقر على مساحة التخزين.
- إذا لم يظهر زر البدء، يعني ذلك أنّ خدمة Cloud Storage متاحة حاليًا.
مفعّلة، ولا تحتاج إلى اتباع الخطوات أدناه.
- انقر على البدء.
- اقرأ بيان إخلاء المسؤولية بشأن قواعد الأمان لمشروعك على Firebase، ثم انقر على التالي.
- يتم اختيار موقع Cloud Storage مسبقًا بالمنطقة نفسها التي اخترتها لقاعدة بيانات Cloud Firestore. انقر على تمّ لإكمال عملية الإعداد.
باستخدام قواعد الأمان التلقائية، يمكن لأي مستخدم تمت مصادقته كتابة أي شيء إلى Cloud Storage. سنجعل مساحة التخزين أكثر أمانًا لاحقًا في هذا الدرس التطبيقي حول الترميز.
4. الربط بمشروعك على Firebase
تتيح لك واجهة سطر أوامر Firebase (CLI) استخدام ميزة "استضافة Firebase" لعرض تطبيق الويب محليًا، بالإضافة إلى نشر تطبيق الويب في مشروع Firebase.
تأكد من وصول سطر الأوامر إلى دليل webframework
المحلي لتطبيقك.
ربط رمز تطبيق الويب بمشروعك على Firebase أولاً، سجِّل الدخول إلى واجهة سطر الأوامر في 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
مباشرةً من 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;
})
}
تحديث البيانات وحذفها
نظرًا إلى عدم وجود أي مشاركة متعلقة بالسفر، يمكن للمرء استنتاج مسار المستند المخزن في 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 في خدمة "السفر"، لذا يمكنك الآن مشاهدتها أثناء العمل.
استخدام وظائف 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
في الدالة الإنشائية للحصول على صفيفة قابلة للملاحظة لجميع الانتقالات.
في حال الحاجة إلى رحلات المستخدم الحالي فقط، يمكنك استخدام الدالة 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 لتخزين الملفات أو الكائنات الثنائية الكبيرة. في هذا التطبيق، ستستخدمه للسماح للمستخدمين بمشاركة صور سفرهم.
على نحو مماثل في Firestore، يتطلب تخزين الملفات وتحديثها باستخدام "مساحة التخزين" معرِّفًا فريدًا لكل ملف.
لننفِّذ الدوالّ في TraveService
:
تحميل ملف
انتقِل إلى src/app/services/travel.service.ts
وأدخِل مساحة تخزين من 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 الأخرى.
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;
}
}
}