مصادقة Firebase — البريد الإلكتروني وكلمة المرور
مصادقة Firebase — البريد الإلكتروني وكلمة المرور
توفر خدمة Firebase Authentication حلاً متكاملاً للواجهة الخلفية لإدارة هوية المستخدمين. في هذا الدرس ستنفذ تسجيل المستخدمين وتسجيل دخولهم باستخدام البريد الإلكتروني وكلمة المرور عبر حزمة firebase_auth لـ Flutter، وستتعلم التعامل مع رموز الأخطاء المنظمة التي يكشفها FirebaseAuthException، وستعرض حالة المستخدم الحالي لبقية أجزاء التطبيق من خلال دفق authStateChanges الدائم.
لماذا نستخدم Firebase Auth؟
بناء نظام المصادقة من الصفر يتطلب تجزئة آمنة لكلمات المرور وإدارة الرموز المميزة وتجديد الجلسات وتدفقات استرداد الحسابات. تتولى Firebase Authentication كل ذلك من جانب الخادم حتى تتمكن من التركيز على تجربة المستخدم. تشمل الفوائد الرئيسية:
- الجلسات الدائمة — يخزن SDK الرمز المميز للهوية محلياً ويجدده تلقائياً.
- دفق
Stream<User?>في الوقت الفعلي يُصدر إشعاراً عند كل تغيير في حالة المصادقة (تسجيل الدخول، الخروج، تجديد الرمز). - رموز أخطاء مكتوبة عبر
FirebaseAuthException.code— دون الحاجة لتحليل استجابات HTTP الخام. - دعم جاهز لمزودين إضافيين (Google وApple والهاتف) لاحقاً دون تغيير بنية تطبيقك.
firebase_auth: ^4.x.x إلى pubspec.yaml. نفّذ flutter pub get قبل المتابعة.تسجيل مستخدم جديد
استدعِ FirebaseAuth.instance.createUserWithEmailAndPassword() لإنشاء حساب جديد. الطريقة غير متزامنة وتُعيد UserCredential يحتوي على كائن User الجديد. اغلف الاستدعاء دائماً في كتلة try/catch للتعامل مع FirebaseAuthException.
مثال على التسجيل
import 'package:firebase_auth/firebase_auth.dart';
Future<void> registerUser(String email, String password) async {
try {
final UserCredential credential =
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: email.trim(),
password: password,
);
final User? user = credential.user;
print('Registered: ${user?.email}');
} on FirebaseAuthException catch (e) {
switch (e.code) {
case 'email-already-in-use':
throw Exception('That email address is already registered.');
case 'invalid-email':
throw Exception('The email address is badly formatted.');
case 'weak-password':
throw Exception('Password must be at least 6 characters.');
default:
throw Exception('Registration failed: ${e.message}');
}
}
}
email.trim() دائماً قبل تمرير العنوان إلى Firebase. مسافة زائلة في النهاية تسبب خطأ invalid-email محيراً للمستخدم الذي لا يستطيع رؤية المسافة البيضاء.تسجيل دخول مستخدم موجود
استخدم signInWithEmailAndPassword() للمستخدمين العائدين. نمط معالجة الأخطاء مطابق للتسجيل، لكن رموز الأخطاء ذات الصلة تختلف.
مثال على تسجيل الدخول
Future<void> signInUser(String email, String password) async {
try {
final UserCredential credential =
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: email.trim(),
password: password,
);
print('Signed in as: ${credential.user?.email}');
} on FirebaseAuthException catch (e) {
switch (e.code) {
case 'user-not-found':
throw Exception('No account found for that email.');
case 'wrong-password':
throw Exception('Incorrect password. Please try again.');
case 'user-disabled':
throw Exception('This account has been disabled.');
case 'too-many-requests':
throw Exception('Too many attempts. Try again later.');
default:
throw Exception('Sign-in failed: ${e.message}');
}
}
}
Future<void> signOutUser() async {
await FirebaseAuth.instance.signOut();
}
الاستماع إلى تغييرات حالة المصادقة
تُعيد FirebaseAuth.instance.authStateChanges() دفقاً من نوع Stream<User?> يُصدر كائن User عند تسجيل الدخول، وnull عند تسجيل الخروج. يُعدّ هذا الدفق الطريقة الموصى بها لقيادة شجرة التنقل في تطبيقك — فهو يحافظ على تزامن التطبيق بأكمله دون إدارة يدوية للأعلام.
اغلف MaterialApp (أو الموجه الخاص به) بـ StreamBuilder للاستجابة لتغييرات المصادقة على مستوى الجذر:
دفق المصادقة على مستوى الجذر
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, AsyncSnapshot<User?> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.hasData && snapshot.data != null) {
return const HomeScreen(); // المستخدم مسجل دخوله
}
return const LoginScreen(); // المستخدم غير مسجل
},
),
);
}
}
FirebaseAuth.instance.currentUser بشكل متزامن عند بدء تشغيل التطبيق لتحديد الشاشة التي ستُعرض. ثمة لحظة وجيزة عند الإطلاق البارد لم يستعد فيها SDK الجلسة المحفوظة بعد، فيُعيد currentUser قيمة null حتى للمستخدم الذي سجّل دخوله سابقاً. استخدم الدفق دائماً.رموز أخطاء FirebaseAuthException الشائعة
فيما يلي مرجع لأهم الرموز التي ستواجهها:
- email-already-in-use — التسجيل: البريد الإلكتروني مستخدم بحساب آخر.
- invalid-email — التسجيل أو تسجيل الدخول: عنوان بريد إلكتروني مشوّه.
- weak-password — التسجيل: كلمة المرور أقصر من 6 أحرف.
- user-not-found — تسجيل الدخول: لا يوجد حساب لهذا البريد الإلكتروني.
- wrong-password — تسجيل الدخول: البريد الصحيح لكن كلمة المرور خاطئة.
- user-disabled — تسجيل الدخول: تم تعليق الحساب في لوحة تحكم Firebase.
- too-many-requests — تسجيل الدخول: الحساب مقفل مؤقتاً بعد محاولات متكررة فاشلة.
- operation-not-allowed — تسجيل الدخول بالبريد/كلمة المرور غير مفعّل في لوحة تحكم Firebase.
ملخص
في هذا الدرس تعلمت كيفية تنفيذ دورة المصادقة الكاملة بالبريد الإلكتروني وكلمة المرور في Flutter باستخدام Firebase Authentication:
- تسجيل مستخدمين جدد باستخدام
createUserWithEmailAndPassword()والتعامل مع رموزFirebaseAuthExceptionالمكتوبة. - تسجيل دخول المستخدمين الموجودين بـ
signInWithEmailAndPassword()وتسجيل خروجهم بـsignOut(). - قيادة تنقل التطبيق بشكل تفاعلي باستخدام دفق
authStateChanges()داخلStreamBuilder. - تطبيق أفضل ممارسات الأمان كتقليم مدخل البريد الإلكتروني واستخدام رسائل خطأ عامة في الإنتاج.