1. Nội dung bạn sẽ tạo
Trong lớp học lập trình này, bạn sẽ xây dựng một blog du lịch có bản đồ cộng tác theo thời gian thực bằng thư viện Angular mới nhất của chúng tôi: AngularFire. Ứng dụng web cuối cùng sẽ bao gồm một blog du lịch, nơi bạn có thể tải hình ảnh lên cho từng địa điểm mà bạn đã ghé thăm.
AngularFire sẽ được dùng để tạo ứng dụng web, Emulator Suite để kiểm thử cục bộ, Xác thực để theo dõi dữ liệu người dùng, Firestore và Storage để duy trì dữ liệu và nội dung nghe nhìn, được hỗ trợ bởi Cloud Functions và cuối cùng là Firebase Hosting để triển khai ứng dụng.
Kiến thức bạn sẽ học được
- Cách phát triển bằng các sản phẩm của Firebase trên thiết bị bằng Bộ công cụ mô phỏng
- Cách cải thiện ứng dụng web bằng AngularFire
- Cách duy trì dữ liệu trong Firestore
- Cách duy trì nội dung nghe nhìn trong Bộ nhớ
- Cách triển khai ứng dụng của bạn lên Firebase Hosting
- Cách sử dụng Cloud Functions để tương tác với cơ sở dữ liệu và API
Bạn cần có
- Node.js phiên bản 10 trở lên
- Một Tài khoản Google để tạo và quản lý Dự án Firebase
- Firebase CLI phiên bản 11.14.2 trở lên
- Một trình duyệt mà bạn chọn, chẳng hạn như Chrome
- Có kiến thức cơ bản về Angular và JavaScript
2. Nhận mã mẫu
Sao chép kho lưu trữ GitHub của lớp học lập trình từ dòng lệnh:
git clone https://github.com/firebase/codelab-friendlychat-web
Ngoài ra, nếu chưa cài đặt git, bạn có thể tải kho lưu trữ xuống dưới dạng tệp ZIP.
Kho lưu trữ Github chứa các dự án mẫu cho nhiều nền tảng.
Lớp học lập trình này chỉ sử dụng kho lưu trữ webframework:
- 📁 webframework: Mã khởi đầu mà bạn sẽ xây dựng trong lớp học lập trình này.
Cài đặt các phần phụ thuộc
Sau khi sao chép, hãy cài đặt các phần phụ thuộc trong thư mục gốc và thư mục functions
trước khi tạo ứng dụng web.
cd webframework && npm install
cd functions && npm install
Cài đặt Giao diện dòng lệnh (CLI) của Firebase
Cài đặt Giao diện dòng lệnh (CLI) của Firebase bằng lệnh sau trong một thiết bị đầu cuối:
npm install -g firebase-tools
Kiểm tra kỹ để đảm bảo phiên bản Firebase CLI của bạn lớn hơn 11.14.2 bằng cách sử dụng:
firebase --version
Nếu phiên bản của bạn thấp hơn 11.14.2, vui lòng cập nhật bằng cách sử dụng:
npm update firebase-tools
3. Tạo và thiết lập dự án Firebase
Tạo dự án Firebase
- Đăng nhập vào bảng điều khiển của Firebase bằng Tài khoản Google của bạn.
- Nhấp vào nút này để tạo một dự án mới, rồi nhập tên dự án (ví dụ:
FriendlyChat
).
- Nhấp vào Tiếp tục.
- Nếu được nhắc, hãy xem xét và chấp nhận các điều khoản của Firebase, rồi nhấp vào Tiếp tục.
- (Không bắt buộc) Bật tính năng hỗ trợ của AI trong bảng điều khiển của Firebase (còn gọi là "Gemini trong Firebase").
- Đối với lớp học lập trình này, bạn không cần Google Analytics, vì vậy hãy tắt lựa chọn Google Analytics.
- Nhấp vào Tạo dự án, đợi dự án được cấp phép rồi nhấp vào Tiếp tục.
Thêm một ứng dụng web Firebase vào dự án
- Nhấp vào biểu tượng web để tạo một ứng dụng web Firebase mới.
- Ở bước tiếp theo, bạn sẽ thấy một đối tượng cấu hình. Sao chép nội dung của đối tượng này vào tệp
environments/environment.ts
.
Thiết lập các sản phẩm của Firebase
Ứng dụng mà chúng ta sẽ tạo sử dụng các sản phẩm Firebase có sẵn cho ứng dụng web:
- Xác thực Firebase để dễ dàng cho phép người dùng đăng nhập vào ứng dụng.
- Cloud Firestore để lưu dữ liệu có cấu trúc trên đám mây và nhận thông báo tức thì khi dữ liệu thay đổi.
- Cloud Storage cho Firebase để lưu tệp trên đám mây.
- Lưu trữ Firebase để lưu trữ và phân phát tài sản của bạn.
- Các hàm để tương tác với API nội bộ và bên ngoài.
Một số sản phẩm trong số này cần có cấu hình đặc biệt hoặc cần được bật bằng cách sử dụng bảng điều khiển của Firebase.
Bật tính năng đăng nhập bằng Google cho Xác thực Firebase
Để cho phép người dùng đăng nhập vào ứng dụng web bằng Tài khoản Google, chúng ta sẽ sử dụng phương thức đăng nhập Google.
Cách bật tính năng đăng nhập bằng Google:
- Trong bảng điều khiển của Firebase, hãy tìm mục Tạo ở bảng điều khiển bên trái.
- Nhấp vào Xác thực, sau đó nhấp vào thẻ Phương thức đăng nhập (hoặc nhấp vào đây để chuyển thẳng đến thẻ này).
- Bật nhà cung cấp dịch vụ đăng nhập Google, sau đó nhấp vào Lưu.
- Đặt tên công khai của ứng dụng thành <your-project-name> và chọn Project support email (Email hỗ trợ dự án) trong trình đơn thả xuống.
Bật Cloud Firestore
- Trong mục Tạo của bảng điều khiển Firebase, hãy nhấp vào Cơ sở dữ liệu Firestore.
- Nhấp vào Tạo cơ sở dữ liệu trong ngăn Cloud Firestore.
- Đặt vị trí lưu trữ dữ liệu Cloud Firestore. Bạn có thể để nguyên lựa chọn mặc định này hoặc chọn một khu vực gần bạn.
Bật Cloud Storage
Ứng dụng web này sử dụng Cloud Storage cho Firebase để lưu trữ, tải lên và chia sẻ ảnh.
- Trong mục Tạo của bảng điều khiển Firebase, hãy nhấp vào Bộ nhớ.
- Nếu không có nút Bắt đầu, thì tức là Cloud Storage đã
đã bật và bạn không cần làm theo các bước bên dưới.
- Nhấp vào Bắt đầu.
- Đọc tuyên bố từ chối trách nhiệm về các quy tắc bảo mật cho dự án Firebase của bạn, rồi nhấp vào Tiếp theo.
- Vị trí Cloud Storage được chọn trước theo cùng khu vực mà bạn đã chọn cho cơ sở dữ liệu Cloud Firestore. Nhấp vào Xong để hoàn tất quá trình thiết lập.
Với các quy tắc bảo mật mặc định, mọi người dùng đã xác thực đều có thể ghi mọi nội dung vào Cloud Storage. Chúng ta sẽ bảo mật bộ nhớ hơn nữa ở phần sau trong lớp học lập trình này.
4. Kết nối với dự án Firebase
Giao diện dòng lệnh (CLI) của Firebase cho phép bạn sử dụng tính năng Lưu trữ Firebase để phân phát ứng dụng web của mình cục bộ, cũng như triển khai ứng dụng web đó cho dự án Firebase.
Đảm bảo rằng dòng lệnh đang truy cập vào thư mục webframework
cục bộ của ứng dụng.
Kết nối mã ứng dụng web với dự án Firebase của bạn. Trước tiên, hãy đăng nhập vào Giao diện dòng lệnh (CLI) của Firebase ở dòng lệnh:
firebase login
Tiếp theo, hãy chạy lệnh sau để tạo một bí danh dự án. Thay $YOUR_PROJECT_ID
bằng mã dự án Firebase của bạn.
firebase use $YOUR_PROJECT_ID
Thêm AngularFire
Để thêm AngularFire vào ứng dụng, hãy chạy lệnh sau:
ng add @angular/fire
Sau đó, hãy làm theo hướng dẫn trên dòng lệnh và chọn các tính năng có trong dự án Firebase của bạn.
Khởi động Firebase
Để chạy dự án Firebase, hãy chạy:
firebase init
Sau đó, làm theo lời nhắc trên dòng lệnh, hãy chọn các tính năng và trình mô phỏng đã được dùng trong dự án Firebase của bạn.
Khởi động trình mô phỏng
Trong thư mục webframework
, hãy chạy lệnh sau để khởi động trình mô phỏng:
firebase emulators:start
Cuối cùng, bạn sẽ thấy nội dung như sau:
$ 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.
Khi bạn thấy thông báo ✔All emulators ready!
, tức là các trình mô phỏng đã sẵn sàng để sử dụng.
Bạn sẽ thấy giao diện người dùng của ứng dụng du lịch, nhưng giao diện này chưa hoạt động (hiện tại):
Bây giờ, hãy bắt đầu xây dựng!
5. Kết nối ứng dụng web với trình mô phỏng
Dựa trên bảng trong nhật ký trình mô phỏng, trình mô phỏng Cloud Firestore đang xử lý trên cổng 8080 và trình mô phỏng Xác thực đang xử lý trên cổng 9099.
Mở EmulatorUI
Trong trình duyệt web, hãy truy cập vào http://127.0.0.1:4000/. Bạn sẽ thấy giao diện người dùng Emulator Suite.
Định tuyến ứng dụng để sử dụng trình mô phỏng
Trong src/app/app.module.ts
, hãy thêm mã sau vào danh sách các nội dung nhập của 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;
}),
...
]
Giờ đây, ứng dụng đã được định cấu hình để sử dụng trình mô phỏng cục bộ, cho phép thực hiện kiểm thử và phát triển cục bộ.
6. Thêm xác thực
Giờ đây, khi đã thiết lập trình mô phỏng cho ứng dụng, chúng ta có thể thêm các tính năng Xác thực để đảm bảo rằng mỗi người dùng đều đã đăng nhập trước khi đăng tin nhắn.
Để làm như vậy, chúng ta có thể nhập trực tiếp các hàm signin
từ AngularFire và theo dõi trạng thái uỷ quyền của người dùng bằng hàm authState
. Sửa đổi các hàm của trang đăng nhập để trang kiểm tra trạng thái uỷ quyền của người dùng khi tải.
Chèn Firebase Auth vào AngularFire
Trong src/app/pages/login-page/login-page.component.ts
, hãy nhập Auth
từ @angular/fire/auth
rồi chèn Auth
vào LoginPageComponent
. Bạn cũng có thể nhập trực tiếp các nhà cung cấp dịch vụ xác thực (chẳng hạn như Google) và các hàm (chẳng hạn như signin
, signout
) từ cùng một gói và sử dụng trong ứng dụng.
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);
})
}
}
Giờ đây, trang đăng nhập đã hoạt động! Hãy thử đăng nhập và xem kết quả trong Trình mô phỏng xác thực.
7. Định cấu hình Firestore
Ở bước này, bạn sẽ thêm chức năng đăng và cập nhật các bài đăng trên blog du lịch được lưu trữ trong Firestore.
Tương tự như Xác thực, các hàm Firestore được đóng gói sẵn trong AngularFire. Mỗi tài liệu thuộc một tập hợp và mỗi tài liệu cũng có thể có các tập hợp lồng nhau. Bạn cần biết path
của tài liệu trong Firestore để tạo và cập nhật bài đăng trên blog du lịch.
Triển khai TravelService
Vì nhiều trang khác nhau sẽ cần đọc và cập nhật các tài liệu Firestore trong ứng dụng web, nên chúng ta có thể triển khai các hàm trong src/app/services/travel.service.ts
để tránh việc liên tục chèn cùng một hàm AngularFire vào mọi trang.
Bắt đầu bằng cách chèn Auth
, tương tự như bước trước, cũng như Firestore
vào dịch vụ của chúng ta. Việc xác định một đối tượng user$
có thể quan sát để theo dõi trạng thái xác thực hiện tại cũng rất hữu ích.
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);
Thêm bài đăng về chuyến đi
Bài đăng về du lịch sẽ tồn tại dưới dạng tài liệu được lưu trữ trong Firestore. Vì tài liệu phải nằm trong các bộ sưu tập, nên bộ sưu tập chứa tất cả bài đăng về du lịch sẽ có tên là travels
. Do đó, đường dẫn của mọi bài đăng về du lịch sẽ là travels/
Khi sử dụng hàm addDoc
của AngularFire, bạn có thể chèn một đối tượng vào một tập hợp:
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;
})
}
Cập nhật và xoá dữ liệu
Với uid của bất kỳ bài đăng nào về du lịch, người dùng có thể suy ra đường dẫn của tài liệu được lưu trữ trong Firestore, sau đó có thể đọc, cập nhật hoặc xoá bằng các hàm updateFoc
và deleteDoc
của 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)
}
Đọc dữ liệu dưới dạng một đối tượng có thể quan sát
Vì bạn có thể sửa đổi bài đăng về chuyến đi và các điểm dừng chân sau khi tạo, nên sẽ hữu ích hơn nếu bạn nhận được các đối tượng tài liệu dưới dạng các đối tượng có thể quan sát được để đăng ký nhận mọi thay đổi được thực hiện. Chức năng này được cung cấp bởi các hàm docData
và collectionData
từ @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[]>
}
Thêm điểm dừng vào bài đăng về chuyến đi
Giờ đây, khi các thao tác đăng bài về du lịch đã được thiết lập, đã đến lúc bạn cân nhắc các điểm dừng. Các điểm dừng này sẽ nằm trong một bộ sưu tập con của bài đăng về du lịch như sau: travels/
Quá trình này gần giống với việc tạo bài đăng về du lịch, vì vậy, hãy thử tự mình triển khai hoặc xem cách triển khai bên dưới:
async addStop(travelId: string) {
...
const ref = await addDoc(collection(this.firestore, `travels/${travelId}/stops`), stopData)
setDoc(ref, {...stopData, id: ref.id})
}
Tuyệt vời! Các hàm Firestore đã được triển khai trong dịch vụ Du lịch, vì vậy, giờ đây bạn có thể thấy các hàm này hoạt động.
Sử dụng các hàm Firestore trong ứng dụng
Chuyển đến src/app/pages/my-travels/my-travels.component.ts
và chèn TravelService
để sử dụng các hàm của nó.
travelService = inject(TravelService);
travelsData$: Observable<Travel[]>;
stopsList$!: Observable<Stop[]>;
constructor() {
this.travelsData$ = this.travelService.getCollectionData(`travels`) as Observable<Travel[]>
}
TravelService
được gọi trong hàm khởi tạo để lấy một mảng Observable gồm tất cả các chuyến đi.
Trong trường hợp chỉ cần thông tin về chuyến đi của người dùng hiện tại, hãy sử dụng hàm query
.
Các phương pháp khác để đảm bảo an ninh bao gồm việc triển khai các quy tắc bảo mật hoặc sử dụng Cloud Functions với Firestore như đã khám phá trong các bước không bắt buộc bên dưới
Sau đó, bạn chỉ cần gọi các hàm được triển khai trong TravelService
.
async createTravel(userId: String) {
this.travelService.addEmptyTravel(userId);
}
deleteTravel(travelId: String) {
this.travelService.deleteData(`travels/${travelId}`)
}
Giờ đây, trang Chuyến đi của tôi sẽ hoạt động bình thường! Hãy xem điều gì sẽ xảy ra trong trình mô phỏng Firestore khi bạn tạo một bài đăng du lịch mới.
Sau đó, lặp lại cho các hàm cập nhật trong /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. Định cấu hình bộ nhớ
Giờ đây, bạn sẽ triển khai Bộ nhớ để lưu trữ hình ảnh và các loại nội dung nghe nhìn khác.
Cloud Firestore phù hợp nhất để lưu trữ dữ liệu có cấu trúc, chẳng hạn như các đối tượng JSON. Cloud Storage được thiết kế để lưu trữ tệp hoặc blob. Trong ứng dụng này, bạn sẽ dùng tính năng này để cho phép người dùng chia sẻ ảnh du lịch của họ.
Tương tự như Firestore, việc lưu trữ và cập nhật tệp bằng Storage yêu cầu mỗi tệp phải có một giá trị nhận dạng riêng biệt.
Hãy triển khai các hàm trong TraveService
:
Tải tệp lên
Chuyển đến src/app/services/travel.service.ts
và chèn Bộ nhớ từ AngularFire:
export class TravelService {
firestore: Firestore = inject(Firestore);
auth: Auth = inject(Auth);
storage: Storage = inject(Storage);
Và triển khai hàm tải lên:
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;
}
Điểm khác biệt chính giữa việc truy cập vào tài liệu từ Firestore và tệp từ Cloud Storage là mặc dù cả hai đều tuân theo các đường dẫn có cấu trúc thư mục, nhưng tổ hợp đường dẫn và URL cơ sở được lấy thông qua getDownloadURL
, sau đó có thể được lưu trữ và sử dụng trong tệp
.
Sử dụng chức năng này trong ứng dụng
Chuyển đến src/app/components/edit-stop/edit-stop.component.ts
rồi gọi hàm tải lên bằng cách sử dụng:
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);
}
Khi hình ảnh được tải lên, chính tệp đa phương tiện đó sẽ được tải lên bộ nhớ và URL sẽ được lưu trữ tương ứng trong tài liệu trong Firestore.
9. Triển khai ứng dụng
Giờ thì chúng ta đã sẵn sàng triển khai ứng dụng!
Sao chép cấu hình firebase
từ src/environments/environment.ts
sang src/environments/environment.prod.ts
rồi chạy:
firebase deploy
Bạn sẽ thấy nội dung như sau:
✔ 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. Xin chúc mừng!
Giờ đây, ứng dụng của bạn đã hoàn tất và được triển khai trên Firebase Hosting! Giờ đây, bạn có thể truy cập vào tất cả dữ liệu và số liệu phân tích trong Bảng điều khiển Firebase.
Để biết thêm các tính năng liên quan đến AngularFire, Functions, quy tắc bảo mật, đừng quên xem các bước không bắt buộc bên dưới cũng như các Lớp học lập trình khác của Firebase!
11. Không bắt buộc: Cơ chế bảo vệ xác thực AngularFire
Cùng với Xác thực Firebase, AngularFire cũng cung cấp các cơ chế bảo vệ dựa trên hoạt động xác thực trên các tuyến đường, để người dùng không có đủ quyền truy cập có thể được chuyển hướng. Điều này giúp bảo vệ ứng dụng khỏi những người dùng truy cập vào dữ liệu được bảo vệ.
Trong src/app/app-routing.module.ts
, hãy nhập
import {AuthGuard, redirectLoggedInTo, redirectUnauthorizedTo} from '@angular/fire/auth-guard'
Sau đó, bạn có thể xác định các hàm về thời điểm và vị trí mà người dùng sẽ được chuyển hướng đến trên một số trang nhất định:
const redirectUnauthorizedToLogin = () => redirectUnauthorizedTo(['signin']);
const redirectLoggedInToTravels = () => redirectLoggedInTo(['my-travels']);
Sau đó, bạn chỉ cần thêm các điểm này vào tuyến đường:
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. Không bắt buộc: quy tắc bảo mật
Cả Firestore và Cloud Storage đều sử dụng các quy tắc bảo mật (firestore.rules
và security.rules
tương ứng) để thực thi tính bảo mật và xác thực dữ liệu.
Hiện tại, dữ liệu Firestore và Storage có quyền truy cập mở để đọc và ghi, nhưng bạn không muốn mọi người thay đổi bài đăng của người khác! Bạn có thể dùng các quy tắc bảo mật để hạn chế quyền truy cập vào các bộ sưu tập và tài liệu của mình.
Quy tắc Firestore
Để chỉ cho phép người dùng đã xác thực xem bài đăng về du lịch, hãy chuyển đến tệp firestore.rules
rồi thêm:
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;
}
}
Bạn cũng có thể dùng quy tắc bảo mật để xác thực dữ liệu:
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;
}
}
Quy tắc lưu trữ
Tương tự, chúng ta có thể sử dụng các quy tắc bảo mật để thực thi quyền truy cập vào cơ sở dữ liệu lưu trữ trong storage.rules
. Xin lưu ý rằng chúng ta cũng có thể dùng các hàm để kiểm tra phức tạp hơn:
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;
}
}
}