Flutter Firebase Authentication

Hướng dẫn tích hợp Firebase Authentication vào ứng dụng Flutter để quản lý người dùng

Flutter Firebase Authentication

Firebase Authentication là một giải pháp xác thực người dùng mạnh mẽ và an toàn được phát triển bởi Google. Nó cung cấp các phương thức xác thực phổ biến như email/mật khẩu, xác thực qua mạng xã hội (Google, Facebook, Twitter,...), xác thực qua số điện thoại và nhiều phương thức khác. Trong bài viết này, chúng ta sẽ tìm hiểu cách tích hợp Firebase Authentication vào ứng dụng Flutter để xây dựng hệ thống quản lý người dùng hoàn chỉnh.

Mục lục

  1. Thiết lập dự án Firebase
  2. Cài đặt các gói phụ thuộc cần thiết
  3. Cấu hình Firebase cho ứng dụng Flutter
  4. Xây dựng các màn hình xác thực
  5. Xác thực với Email và Mật khẩu
  6. Xác thực với Google
  7. Xác thực với Facebook
  8. Xác thực với Số điện thoại
  9. Quản lý trạng thái người dùng
  10. Phân quyền và Bảo mật
  11. Các kỹ thuật nâng cao
  12. Xử lý lỗi
  13. Kết luận

1. Thiết lập dự án Firebase

Bước 1: Tạo dự án Firebase

  1. Truy cập Firebase Console
  2. Nhấp vào "Thêm dự án" (hoặc "Add project")
  3. Nhập tên dự án, ví dụ: "Flutter Auth Demo"
  4. Tùy chọn bật Google Analytics cho dự án (khuyến nghị)
  5. Nhấp "Tiếp tục" và làm theo các bước để hoàn thành quá trình tạo dự án

Bước 2: Bật Firebase Authentication

  1. Trong Firebase Console, chọn dự án vừa tạo
  2. Từ menu bên trái, chọn "Authentication"
  3. Nhấp vào tab "Sign-in method"
  4. Bật các phương thức xác thực mà bạn muốn sử dụng (ví dụ: Email/Password, Google, Facebook, Phone)
  5. Cấu hình thêm các thông tin cần thiết cho từng phương thức
Flutter Firebase Authentication

2. Cài đặt các gói phụ thuộc cần thiết

Mở file pubspec.yaml của dự án Flutter và thêm các gói sau:

dependencies: flutter: sdk: flutter firebase_core: ^2.13.0 firebase_auth: ^4.6.1 google_sign_in: ^6.1.0 flutter_facebook_auth: ^5.0.11 provider: ^6.0.5

Chạy lệnh sau để cài đặt các gói:

flutter pub get

3. Cấu hình Firebase cho ứng dụng Flutter

Cấu hình cho Android

Bước 1: Đăng ký ứng dụng Android

  1. Trong Firebase Console, chọn dự án của bạn
  2. Nhấp vào biểu tượng Android để thêm ứng dụng Android
  3. Nhập ID gói của ứng dụng Android (ví dụ: com.example.flutter_auth_demo)
  4. (Tùy chọn) Nhập nickname cho ứng dụng
  5. Đăng ký ứng dụng

Bước 2: Tải xuống file cấu hình

  1. Tải xuống file google-services.json
  2. Đặt file này vào thư mục android/app của dự án Flutter

Bước 3: Cập nhật Gradle

Mở file android/build.gradle và thêm:

buildscript { dependencies { // ... other dependencies classpath 'com.google.gms:google-services:4.3.15' } }

Mở file android/app/build.gradle và thêm:

// Bottom of the file apply plugin: 'com.google.gms.google-services'

Cấu hình cho iOS

Bước 1: Đăng ký ứng dụng iOS

  1. Trong Firebase Console, chọn dự án của bạn
  2. Nhấp vào biểu tượng iOS để thêm ứng dụng iOS
  3. Nhập ID gói của ứng dụng iOS (ví dụ: com.example.flutterAuthDemo)
  4. (Tùy chọn) Nhập nickname cho ứng dụng
  5. Đăng ký ứng dụng

Bước 2: Tải xuống file cấu hình

  1. Tải xuống file GoogleService-Info.plist
  2. Sử dụng Xcode, thêm file này vào thư mục Runner của dự án (đảm bảo chọn "Copy items if needed")

Bước 3: Cập nhật Podfile

Mở file ios/Podfile và thêm:

platform :ios, '12.0'

4. Xây dựng các màn hình xác thực

Chúng ta sẽ xây dựng các màn hình xác thực cơ bản cho ứng dụng:

Màn hình đăng nhập (login_screen.dart)

import 'package:flutter/material.dart'; import 'package:firebase_auth/firebase_auth.dart'; import '../services/auth_service.dart'; class LoginScreen extends StatefulWidget { @override _LoginScreenState createState() => _LoginScreenState(); } class _LoginScreenState extends State<LoginScreen> { final AuthService _authService = AuthService(); final _formKey = GlobalKey<FormState>(); String _email = ''; String _password = ''; String _error = ''; bool _isLoading = false; void _signInWithEmailAndPassword() async { if (_formKey.currentState!.validate()) { setState(() { _isLoading = true; _error = ''; }); try { await _authService.signInWithEmailAndPassword(_email, _password); // Đăng nhập thành công, NavigationService sẽ điều hướng người dùng } catch (e) { setState(() { _error = _handleFirebaseAuthError(e); _isLoading = false; }); } } } String _handleFirebaseAuthError(dynamic e) { if (e is FirebaseAuthException) { switch (e.code) { case 'user-not-found': return 'Không tìm thấy tài khoản với email này.'; case 'wrong-password': return 'Sai mật khẩu.'; case 'invalid-email': return 'Email không hợp lệ.'; case 'user-disabled': return 'Tài khoản đã bị vô hiệu hóa.'; default: return 'Đăng nhập thất bại: ${e.message}'; } } return 'Đã xảy ra lỗi không xác định.'; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Đăng nhập'), ), body: Center( child: SingleChildScrollView( padding: EdgeInsets.all(16.0), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Image.asset( 'assets/images/logo.png', height: 100, ), SizedBox(height: 48.0), TextFormField( decoration: InputDecoration( labelText: 'Email', border: OutlineInputBorder(), prefixIcon: Icon(Icons.email), ), keyboardType: TextInputType.emailAddress, validator: (value) { if (value == null || value.isEmpty) { return 'Vui lòng nhập email'; } return null; }, onChanged: (value) { _email = value.trim(); }, ), SizedBox(height: 16.0), TextFormField( decoration: InputDecoration( labelText: 'Mật khẩu', border: OutlineInputBorder(), prefixIcon: Icon(Icons.lock), ), obscureText: true, validator: (value) { if (value == null || value.isEmpty) { return 'Vui lòng nhập mật khẩu'; } return null; }, onChanged: (value) { _password = value; }, ), SizedBox(height: 24.0), if (_error.isNotEmpty) Padding( padding: EdgeInsets.only(bottom: 16.0), child: Text( _error, style: TextStyle(color: Colors.red), textAlign: TextAlign.center, ), ), ElevatedButton( onPressed: _isLoading ? null : _signInWithEmailAndPassword, child: _isLoading ? CircularProgressIndicator(color: Colors.white) : Text('ĐĂNG NHẬP'), style: ElevatedButton.styleFrom( padding: EdgeInsets.symmetric(vertical: 16.0), ), ), SizedBox(height: 16.0), OutlinedButton.icon( icon: Image.asset( 'assets/images/google_logo.png', height: 24.0, ), label: Text('Đăng nhập với Google'), onPressed: _isLoading ? null : () async { setState(() { _isLoading = true; _error = ''; }); try { await _authService.signInWithGoogle(); // Đăng nhập thành công } catch (e) { setState(() { _error = 'Đăng nhập Google thất bại: $e'; _isLoading = false; }); } }, style: OutlinedButton.styleFrom( padding: EdgeInsets.symmetric(vertical: 12.0), ), ), SizedBox(height: 16.0), TextButton( child: Text('Chưa có tài khoản? Đăng ký ngay'), onPressed: () { Navigator.pushNamed(context, '/register'); }, ), ], ), ), ), ), ); } }

Màn hình đăng ký (register_screen.dart)

import 'package:flutter/material.dart'; import 'package:firebase_auth/firebase_auth.dart'; import '../services/auth_service.dart'; class RegisterScreen extends StatefulWidget { @override _RegisterScreenState createState() => _RegisterScreenState(); } class _RegisterScreenState extends State<RegisterScreen> { final AuthService _authService = AuthService(); final _formKey = GlobalKey<FormState>(); String _email = ''; String _password = ''; String _confirmPassword = ''; String _error = ''; bool _isLoading = false; void _registerWithEmailAndPassword() async { if (_formKey.currentState!.validate()) { setState(() { _isLoading = true; _error = ''; }); try { await _authService.registerWithEmailAndPassword(_email, _password); // Đăng ký thành công, NavigationService sẽ điều hướng người dùng } catch (e) { setState(() { _error = _handleFirebaseAuthError(e); _isLoading = false; }); } } } String _handleFirebaseAuthError(dynamic e) { if (e is FirebaseAuthException) { switch (e.code) { case 'email-already-in-use': return 'Email này đã được sử dụng.'; case 'invalid-email': return 'Email không hợp lệ.'; case 'operation-not-allowed': return 'Đăng ký với email và mật khẩu chưa được bật.'; case 'weak-password': return 'Mật khẩu quá yếu.'; default: return 'Đăng ký thất bại: ${e.message}'; } } return 'Đã xảy ra lỗi không xác định.'; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Đăng ký'), ), body: Center( child: SingleChildScrollView( padding: EdgeInsets.all(16.0), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Image.asset( 'assets/images/logo.png', height: 100, ), SizedBox(height: 48.0), TextFormField( decoration: InputDecoration( labelText: 'Email', border: OutlineInputBorder(), prefixIcon: Icon(Icons.email), ), keyboardType: TextInputType.emailAddress, validator: (value) { if (value == null || value.isEmpty) { return 'Vui lòng nhập email'; } return null; }, onChanged: (value) { _email = value.trim(); }, ), SizedBox(height: 16.0), TextFormField( decoration: InputDecoration( labelText: 'Mật khẩu', border: OutlineInputBorder(), prefixIcon: Icon(Icons.lock), ), obscureText: true, validator: (value) { if (value == null || value.isEmpty) { return 'Vui lòng nhập mật khẩu'; } if (value.length < 6) { return 'Mật khẩu phải có ít nhất 6 ký tự'; } return null; }, onChanged: (value) { _password = value; }, ), SizedBox(height: 16.0), TextFormField( decoration: InputDecoration( labelText: 'Xác nhận mật khẩu', border: OutlineInputBorder(), prefixIcon: Icon(Icons.lock_outline), ), obscureText: true, validator: (value) { if (value == null || value.isEmpty) { return 'Vui lòng xác nhận mật khẩu'; } if (value != _password) { return 'Mật khẩu không khớp'; } return null; }, onChanged: (value) { _confirmPassword = value; }, ), SizedBox(height: 24.0), if (_error.isNotEmpty) Padding( padding: EdgeInsets.only(bottom: 16.0), child: Text( _error, style: TextStyle(color: Colors.red), textAlign: TextAlign.center, ), ), ElevatedButton( onPressed: _isLoading ? null : _registerWithEmailAndPassword, child: _isLoading ? CircularProgressIndicator(color: Colors.white) : Text('ĐĂNG KÝ'), style: ElevatedButton.styleFrom( padding: EdgeInsets.symmetric(vertical: 16.0), ), ), SizedBox(height: 16.0), TextButton( child: Text('Đã có tài khoản? Đăng nhập ngay'), onPressed: () { Navigator.pop(context); }, ), ], ), ), ), ), ); } }

5. Xác thực với Email và Mật khẩu

Tạo một service class để xử lý xác thực (lib/services/auth_service.dart):

import 'package:firebase_auth/firebase_auth.dart'; class AuthService { final FirebaseAuth _auth = FirebaseAuth.instance; // Lấy thông tin người dùng hiện tại User? get currentUser => _auth.currentUser; // Stream thông tin người dùng (để lắng nghe trạng thái đăng nhập) Stream<User?> get authStateChanges => _auth.authStateChanges(); // Đăng nhập với email và mật khẩu Future<UserCredential> signInWithEmailAndPassword(String email, String password) async { try { return await _auth.signInWithEmailAndPassword( email: email, password: password, ); } catch (e) { rethrow; } } // Đăng ký với email và mật khẩu Future<UserCredential> registerWithEmailAndPassword(String email, String password) async { try { return await _auth.createUserWithEmailAndPassword( email: email, password: password, ); } catch (e) { rethrow; } } // Đăng xuất Future<void> signOut() async { await _auth.signOut(); } // Quên mật khẩu Future<void> resetPassword(String email) async { await _auth.sendPasswordResetEmail(email: email); } }

13. Kết luận

Flutter Firebase Authentication

Firebase Authentication cung cấp một giải pháp xác thực mạnh mẽ và linh hoạt cho ứng dụng Flutter của bạn. Việc tích hợp Firebase Authentication giúp bạn:

  1. Tiết kiệm thời gian phát triển: Không cần xây dựng hệ thống xác thực từ đầu
  2. Bảo mật cao: Firebase cung cấp các cơ chế bảo mật tiên tiến
  3. Hỗ trợ nhiều phương thức xác thực: Email/mật khẩu, Google, Facebook, số điện thoại,...
  4. Dễ dàng mở rộng: Liên kết với Firebase Firestore để lưu trữ thông tin người dùng
  5. Quản lý người dùng đơn giản: Giao diện Firebase Console thân thiện

Bằng cách tích hợp Firebase Authentication vào ứng dụng Flutter, bạn đã xây dựng một hệ thống xác thực toàn diện, bảo mật, và dễ dàng mở rộng. Hệ thống này có thể đáp ứng nhu cầu của các ứng dụng từ đơn giản đến phức tạp, giúp bạn tập trung vào phát triển các tính năng cốt lõi của ứng dụng.

Hãy luôn cập nhật các gói Firebase mới nhất để đảm bảo ứng dụng của bạn luôn nhận được các cải tiến và bản vá bảo mật mới nhất.

Tài nguyên học tập thêm:

Chúc bạn thành công trong việc xây dựng hệ thống xác thực cho ứng dụng Flutter!