📜  Flutter – 使用 Firebase 设计电子邮件身份验证系统

📅  最后修改于: 2021-09-02 05:16:57             🧑  作者: Mango

Flutter是使用单一代码库开发跨平台应用程序的绝佳工具。虽然Flutter很有用,但当您添加 Firebase 时它会变得更好。在本文中,我们将讨论如何使用 Firebase 在Flutter实现电子邮件/密码身份验证过程。

在本文中,我们将介绍以下flutter开发方面:

  • 改进的小部件树。
  • TextFormField 验证逻辑。
  • 切换密码文本可见性。
  • 处理 UI 中的身份验证错误。
  • 具有加载状态的自定义提交按钮。
  • UI 逻辑和 Firebase 身份验证逻辑,分开。

注意:在深入研究 Firebase 身份验证之前,请在Flutter应用程序中配置 Firebase。检查此链接以获取带有flutter的初始 firebase 设置。

项目预览

现在,让我们来看看实现。

第 1 步:安装和初始化 Firebase

安装:

在使用任何 Firebase 服务之前,您必须首先安装firebase_core 插件,该插件负责将您的应用程序连接到 Firebase。将插件添加到您的pubspec.yaml 文件中。此外,添加一些用于处理身份验证流程的支持插件。

项目/lib/pubspec.yaml

dependencies:
  flutter:
    sdk: flutter

firebase_core: "0.5.2"
firebase_auth: "^0.18.3"
provider: ^4.3.2+2
cloud_firestore: ^0.14.3
font_awesome_flutter: ^8.10.0

通过从项目根目录运行以下命令来安装插件:

$ flutter pub get

初始化 Firebase

要初始化 Firebase,请在 Firebase 类上调用.initializeApp() 方法,如下面的代码所述。这个方法是异步的并返回一个 Future,所以我们需要在显示我们的主应用程序之前确保它已经完成。更新main 的 main()方法。dart

项目/库/主。dart

Future main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}

第 2 步:Firebase 身份验证服务

认证流程:

/libservices/authentication_service.dart

创建一个新文件夹作为服务,并在其中创建一个新的dart文件作为authentication_service。 dart ,它将包含所有身份验证逻辑,以帮助我们分离 UI 逻辑。

authentication_service.dart
Dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_auth_example/models/user_model.dart';
  
class AuthenticationService {
  final FirebaseAuth _firebaseAuth;
  UserModel userModel = UserModel();
  final userRef = Firestore.instance.collection("users");
  
  AuthenticationService(this._firebaseAuth);
  
  // managing the user state via stream. 
  // stream provides an immediate event of
  // the user's current authentication state,
  // and then provides subsequent events whenever
  // the authentication state changes.
  Stream get authStateChanges => _firebaseAuth.authStateChanges();
  
  //1
  Future signIn({String email, String password}) async {
    try {
      await _firebaseAuth.signInWithEmailAndPassword(
          email: email, password: password);
  
      return "Signed In";
    } on FirebaseAuthException catch (e) {
      if (e.code == 'user-not-found') {
        return "No user found for that email.";
      } else if (e.code == 'wrong-password') {
        return "Wrong password provided for that user.";
      } else {
        return "Something Went Wrong.";
      }
    }
  }
  
  //2
  Future signUp({String email, String password}) async {
    try {
      await _firebaseAuth.createUserWithEmailAndPassword(
          email: email, password: password);
      return "Signed Up";
    } on FirebaseAuthException catch (e) {
      if (e.code == 'weak-password') {
        return "The password provided is too weak.";
      } else if (e.code == 'email-already-in-use') {
        return "The account already exists for that email.";
      } else {
        return "Something Went Wrong.";
      }
    } catch (e) {
      print(e);
    }
  }
  
  //3
  Future addUserToDB(
      {String uid, String username, String email, DateTime timestamp}) async {
    userModel = UserModel(
        uid: uid, username: username, email: email, timestamp: timestamp);
  
    await userRef.document(uid).setData(userModel.toMap(userModel));
  }
  
  //4
  Future getUserFromDB({String uid}) async {
    final DocumentSnapshot doc = await userRef.document(uid).get();
  
    //print(doc.data());
  
    return UserModel.fromMap(doc.data());
  }
    
   //5
  Future signOut() async {
    await _firebaseAuth.signOut();
  }
}


Dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
  
class UserModel {
  String email;
  String uid;
  String username;
  DateTime timestamp;
  
  UserModel({this.email, this.uid, this.username, this.timestamp});
  
  Map toMap(UserModel user) {
    var data = Map();
  
    data["uid"] = user.uid;
    data["username"] = user.username;
    data["email"] = user.email;
    data["timestamp"] = user.timestamp;
  
    return data;
  }
  
  UserModel.fromMap(Map mapData) {
    this.uid = mapData["uid"];
    this.username = mapData["username"];
    this.email = mapData["email"];
  }
}


Dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_auth_example/pages/auth_screen_view.dart';
import 'package:flutter_auth_example/pages/home_page.dart';
import 'package:flutter_auth_example/services/authentication_service.dart';
import 'package:provider/provider.dart';
  
Future main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}
  
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        Provider(
          create: (_) => AuthenticationService(FirebaseAuth.instance),
        ),
        StreamProvider(
            create: (context) =>
                context.read().authStateChanges),
      ],
      child: MaterialApp(
        theme: ThemeData(
            brightness: Brightness.dark,
            primaryColor: Colors.green[400],
            accentColor: Colors.deepOrange[200]),
        home: AuthenticationWrapper(),
      ),
    );
  }
}
  
class AuthenticationWrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final firebaseUser = context.watch();
  
    if (firebaseUser != null) {
      //If the user is successfully Logged-In.
      return HomePage();
    } else {
      //If the user is not Logged-In.
      return AuthScreenView();
    }
  }
}


Dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_auth_example/pages/login_page.dart';
import 'package:flutter_auth_example/pages/register_page.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
  
class AuthScreenView extends StatefulWidget {
  @override
  _AuthScreenViewState createState() => _AuthScreenViewState();
}
  
class _AuthScreenViewState extends State {
  PageController pageController;
  int pageIndex = 0;
  
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    pageController = PageController();
  }
  
  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    pageController.dispose();
  }
  
  onPageChanged(int pageIndex) {
    setState(() {
      this.pageIndex = pageIndex;
    });
  }
  
  onTap(int pageIndex) {
    //pageController.jumpToPage(pageIndex);
    pageController.animateToPage(pageIndex,
        duration: Duration(milliseconds: 300), curve: Curves.easeInOut);
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: PageView(
        children: [
            
          //when pageIndex == 0
          LoginPage(), 
            
          //when pageIndex == 1
          RegisterPage()
                  ],
        controller: pageController,
        onPageChanged: onPageChanged,
      ),
      bottomNavigationBar: CupertinoTabBar(
        currentIndex: pageIndex,
        onTap: onTap,
        activeColor: Theme.of(context).primaryColor,
        items: [
          BottomNavigationBarItem(
              title: Text("Log-In"),
              icon: Icon(
                FontAwesomeIcons.signInAlt,
              )),
          BottomNavigationBarItem(
              title: Text("Register"),
              icon: Icon(
                FontAwesomeIcons.userPlus,
              )),
        ],
      ),
    );
  }
}


Dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_auth_example/services/authentication_service.dart';
import 'package:provider/provider.dart';
  
class RegisterPage extends StatefulWidget {
  @override
  _RegisterPageState createState() => _RegisterPageState();
}
  
class _RegisterPageState extends State {
    
  //To Toggle Password Text Visibility.
  bool _obscureText = true; 
  String _username, _email, _password;
    
  //For the loading state.
  bool _isSubmitting; 
  
  final _formKey = GlobalKey();
  final _scaffoldKey = GlobalKey();
  
  FirebaseAuth auth = FirebaseAuth.instance;
  final DateTime timestamp = DateTime.now();
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(title: Text("GeeksForGeeks"), centerTitle: true),
      body: Container(
        padding: EdgeInsets.symmetric(horizontal: 20),
        child: Center(
          child: SingleChildScrollView(
            child: Form(
              key: _formKey,
              child: Column(
                children: [
                  _showTitle(),
                  _showUsernameInput(),
                  _showEmailInput(),
                  _showPasswordInput(),
                  _showFormActions()
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
  
  //1
  _showTitle() {
    return Text(
      "Register",
      style: TextStyle(fontSize: 72, fontWeight: FontWeight.bold),
    );
  }
  
  //2
  _showUsernameInput() {
    return Padding(
      padding: EdgeInsets.only(top: 20),
      child: TextFormField(
        onSaved: (val) => _username = val,
        validator: (val) => val.length < 6 ? "Username is too short." : null,
        decoration: InputDecoration(
            border: OutlineInputBorder(),
            labelText: "Username",
            hintText: "Enter Valid Username",
            icon: Icon(
              Icons.face,
              color: Colors.grey,
            )),
      ),
    );
  }
  
  //3
  _showEmailInput() {
    return Padding(
      padding: EdgeInsets.only(top: 20),
      child: TextFormField(
        onSaved: (val) => _email = val,
        validator: (val) => !val.contains("@") ? "Invalid Email" : null,
        decoration: InputDecoration(
            border: OutlineInputBorder(),
            labelText: "Email",
            hintText: "Enter Valid Email",
            icon: Icon(
              Icons.mail,
              color: Colors.grey,
            )),
      ),
    );
  }
  
  //4
  _showPasswordInput() {
    return Padding(
      padding: EdgeInsets.only(top: 20),
      child: TextFormField(
        onSaved: (val) => _password = val,
        validator: (val) => val.length < 6 ? "Password Is Too Short" : null,
        obscureText: _obscureText,
        decoration: InputDecoration(
            suffixIcon: GestureDetector(
              onTap: () {
                setState(() {
                  _obscureText = !_obscureText;
                });
              },
              child:
                  Icon(_obscureText ? Icons.visibility_off : Icons.visibility),
            ),
            border: OutlineInputBorder(),
            labelText: "Password",
            hintText: "Enter Valid Password",
            icon: Icon(
              Icons.lock,
              color: Colors.grey,
            )),
      ),
    );
  }
  
  //5
  _showFormActions() {
    return Padding(
      padding: EdgeInsets.only(top: 20),
      child: Column(
        children: [
          _isSubmitting == true
              ? CircularProgressIndicator(
                  valueColor:
                      AlwaysStoppedAnimation(Theme.of(context).primaryColor),
                )
              : RaisedButton(
                  child: Text(
                    "Submit",
                    style: TextStyle(color: Colors.black, fontSize: 18),
                  ),
                  elevation: 8.0,
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.all(Radius.circular(10))),
                  color: Colors.orange,
                  onPressed: _submit),
        ],
      ),
    );
  }
  
  //6
  _submit() {
    final _form = _formKey.currentState;
    if (_form.validate()) {
      _form.save();
      //print("Email $_email, Password $_password, Username $_username");
      _registerUser();
    } else {
      print("Form is Invalid");
    }
  }
    
  //7
  _registerUser() async {
    setState(() {
      _isSubmitting = true;
    });
  
    final logMessage = await context
        .read()
        .signUp(email: _email, password: _password);
  
    logMessage == "Signed Up"
        ? _showSuccessSnack(logMessage)
        : _showErrorSnack(logMessage);
  
    print(logMessage);
  
    if (logMessage == "Signed Up") {
      createUserInFirestore();
    } else {
      setState(() {
        _isSubmitting = false;
      });
    }
  }
  
  //When User "Signed Up", success snack will display.
  _showSuccessSnack(String message) {
    final snackbar = SnackBar(
      backgroundColor: Colors.black,
      content: Text(
        "$message",
        style: TextStyle(color: Colors.green),
      ),
    );
    _scaffoldKey.currentState.showSnackBar(snackbar);
    _formKey.currentState.reset();
  }
  
  //When FirebaseAuth Catches error, error snack will display.
  _showErrorSnack(String message) {
    final snackbar = SnackBar(
      backgroundColor: Colors.black,
      content: Text(
        "$message",
        style: TextStyle(color: Colors.red),
      ),
    );
    _scaffoldKey.currentState.showSnackBar(snackbar);
  }
  
  createUserInFirestore() async {
    context.read().addUserToDB(
        uid: auth.currentUser.uid,
        username: _username,
        email: auth.currentUser.email,
        timestamp: timestamp);
  }
}


Dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_auth_example/services/authentication_service.dart';
import 'package:provider/provider.dart';
  
class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}
  
class _LoginPageState extends State {
  bool _obscureText = true;
  String _email, _password;
  bool _isSubmitting;
  
  final _formKey = GlobalKey();
  final _scaffoldKey = GlobalKey();
  
  FirebaseAuth auth = FirebaseAuth.instance;
  final DateTime timestamp = DateTime.now();
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(
        centerTitle: true,
        title: Text("GeeksForGeeks"),
      ),
      body: Container(
        padding: EdgeInsets.symmetric(horizontal: 20),
        child: Center(
          child: SingleChildScrollView(
            child: Form(
              key: _formKey,
              child: Column(
                children: [
                  _showTitle(),
                  _showEmailInput(),
                  _showPasswordInput(),
                  _showFormActions()
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
  
  _showTitle() {
    return Text(
      "Login",
      style: TextStyle(fontSize: 72, fontWeight: FontWeight.bold),
    );
  }
  
  _showEmailInput() {
    return Padding(
      padding: EdgeInsets.only(top: 20),
      child: TextFormField(
        onSaved: (val) => _email = val,
        validator: (val) => !val.contains("@") ? "Invalid Email" : null,
        decoration: InputDecoration(
            border: OutlineInputBorder(),
            labelText: "Email",
            hintText: "Enter Valid Email",
            icon: Icon(
              Icons.mail,
              color: Colors.grey,
            )),
      ),
    );
  }
  
  _showPasswordInput() {
    return Padding(
      padding: EdgeInsets.only(top: 20),
      child: TextFormField(
        onSaved: (val) => _password = val,
        validator: (val) => val.length < 6 ? "Password Is Too Short" : null,
        obscureText: _obscureText,
        decoration: InputDecoration(
            suffixIcon: GestureDetector(
              onTap: () {
                setState(() {
                  _obscureText = !_obscureText;
                });
              },
              child:
                  Icon(_obscureText ? Icons.visibility_off : Icons.visibility),
            ),
            border: OutlineInputBorder(),
            labelText: "Password",
            hintText: "Enter Valid Password",
            icon: Icon(
              Icons.lock,
              color: Colors.grey,
            )),
      ),
    );
  }
  
  _showFormActions() {
    return Padding(
      padding: EdgeInsets.only(top: 20),
      child: Column(
        children: [
          _isSubmitting == true
              ? CircularProgressIndicator(
                  valueColor:
                      AlwaysStoppedAnimation(Theme.of(context).primaryColor),
                )
              : RaisedButton(
                  child: Text(
                    "Submit",
                    style: TextStyle(color: Colors.black, fontSize: 18),
                  ),
                  elevation: 8.0,
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.all(Radius.circular(10))),
                  color: Colors.orange,
                  onPressed: _submit),
        ],
      ),
    );
  }
  
  _submit() {
    final _form = _formKey.currentState;
    if (_form.validate()) {
      _form.save();
      //print("Email $_email, Password $_password");
      _LoginUser();
    } else {
      print("Form is Invalid");
    }
  }
  
  _LoginUser() async {
    setState(() {
      _isSubmitting = true;
    });
  
    final logMessage = await context
        .read()
        .signIn(email: _email, password: _password);
  
    logMessage == "Signed In"
        ? _showSuccessSnack(logMessage)
        : _showErrorSnack(logMessage);
  
    //print("I am logMessage $logMessage");
  
    if (logMessage == "Signed In") {
      return;
    } else {
      setState(() {
        _isSubmitting = false;
      });
    }
  }
  
  _showSuccessSnack(String message) async {
    final snackbar = SnackBar(
      backgroundColor: Colors.black,
      content: Text(
        "$message",
        style: TextStyle(color: Colors.green),
      ),
    );
    _scaffoldKey.currentState.showSnackBar(snackbar);
    _formKey.currentState.reset();
  }
  
  _showErrorSnack(String message) {
    final snackbar = SnackBar(
      backgroundColor: Colors.black,
      content: Text(
        "$message",
        style: TextStyle(color: Colors.red),
      ),
    );
    _scaffoldKey.currentState.showSnackBar(snackbar);
    setState(() {
      _isSubmitting = false;
    });
  }
}


Dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_auth_example/models/user_model.dart';
import 'package:flutter_auth_example/services/authentication_service.dart';
import 'package:provider/provider.dart';
  
class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}
  
class _HomePageState extends State {
  FirebaseAuth auth = FirebaseAuth.instance;
  final userRef = Firestore.instance.collection("users");
  UserModel _currentUser;
  
  String _uid;
  String _username;
  String _email;
  
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    getCurrentUser();
  }
  
  getCurrentUser() async {
    UserModel currentUser = await context
        .read()
        .getUserFromDB(uid: auth.currentUser.uid);
  
    _currentUser = currentUser;
  
    print("${_currentUser.username}");
  
    setState(() {
      _uid = _currentUser.uid;
      _username = _currentUser.username;
      _email = _currentUser.email;
    });
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("HomePage"),
        centerTitle: true,
      ),
      body: _currentUser == null
          ? Center(child: CircularProgressIndicator())
          : Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text(
                  "uid is ${_uid} , email is ${_email}, name is ${_username}",
                  textAlign: TextAlign.center,
                ),
                Center(
                  child: RaisedButton(
                    child: Text(
                      "Logout",
                      style: TextStyle(color: Colors.black, fontSize: 18),
                    ),
                    elevation: 8.0,
                    shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.all(Radius.circular(10))),
                    color: Colors.orange,
                    onPressed: () {
                      context.read().signOut();
                    },
                  ),
                ),
              ],
            ),
    );
  }
}


/libmodels/user_model.dart

Dart

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
  
class UserModel {
  String email;
  String uid;
  String username;
  DateTime timestamp;
  
  UserModel({this.email, this.uid, this.username, this.timestamp});
  
  Map toMap(UserModel user) {
    var data = Map();
  
    data["uid"] = user.uid;
    data["username"] = user.username;
    data["email"] = user.email;
    data["timestamp"] = user.timestamp;
  
    return data;
  }
  
  UserModel.fromMap(Map mapData) {
    this.uid = mapData["uid"];
    this.username = mapData["username"];
    this.email = mapData["email"];
  }
}

用户模型。 dart只是一个普通的旧Dart对象策略,用于将用户模型转换为 Map 并将其作为 Map 检索,就像它基本上是 JSON 对象一样。

身份验证服务。dart文件:

以下是 authentication_service 中使用的方法。dart文件:

1. 登录({字符串电子邮件,字符串密码})

  • 此方法接受电子邮件和密码作为参数。
  • 电子邮件和密码用于登录用户。
  • 当用户“登录”时,它会返回一条适当的消息。
  • FirebaseAuthException捕获错误时,它会返回适当的消息。

2.注册({字符串电子邮件,字符串密码})

  • 此方法接受电子邮件和密码作为参数。
  • 电子邮件和密码用于注册用户。
  • 它返回当用户“签署了”相应的消息。
  • FirebaseAuthException捕获错误时,它会返回适当的消息。

3. addUserToDB({String uid, String username, String email, DateTime timestamp})

  • 此方法接受用户uid 、用户名、电子邮件和用户的当前时间戳( DateTime.now( ) )作为参数。
  • Cloud Firestore 数据库中创建当前用户的新文档。 (请从您的 Firebase 项目控制台启用云Firestore )。文档名称应该是用户的uid
  • 该方法只能在当前用户是新用户时触发,即初始点在我们的应用程序中注册的用户。

4. getUserFromDB({String uid})

  • 此方法接受当前用户uid作为参数。
  • 它将帮助我们从 Cloud Firestore数据库中获取当前用户的存储数据。

5.退出()

  • 此方法仅用于从应用程序中注销用户。

步骤 4:检查身份验证状态

在我们的main中将AuthenticationService方法注册为 Provider 。dart文件。

项目/库/主。dart

Dart

import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_auth_example/pages/auth_screen_view.dart';
import 'package:flutter_auth_example/pages/home_page.dart';
import 'package:flutter_auth_example/services/authentication_service.dart';
import 'package:provider/provider.dart';
  
Future main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}
  
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        Provider(
          create: (_) => AuthenticationService(FirebaseAuth.instance),
        ),
        StreamProvider(
            create: (context) =>
                context.read().authStateChanges),
      ],
      child: MaterialApp(
        theme: ThemeData(
            brightness: Brightness.dark,
            primaryColor: Colors.green[400],
            accentColor: Colors.deepOrange[200]),
        home: AuthenticationWrapper(),
      ),
    );
  }
}
  
class AuthenticationWrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final firebaseUser = context.watch();
  
    if (firebaseUser != null) {
      //If the user is successfully Logged-In.
      return HomePage();
    } else {
      //If the user is not Logged-In.
      return AuthScreenView();
    }
  }
}

mainAuthenticationWrapper。 dart,检查用户的状态。如果用户未登录,它将显示AuthScreenView() ,如果用户已登录,它将显示HomePage()

第 5 步:根据身份验证状态在 ScreenView 之间切换。

AuthScreenView():

/lib/pages/auth_screen_view.dart

AuthScreenView只是一个pageview ,它处理LoginPage()RegisterPage()之间的切换。

auth_screen_view.dart

Dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_auth_example/pages/login_page.dart';
import 'package:flutter_auth_example/pages/register_page.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
  
class AuthScreenView extends StatefulWidget {
  @override
  _AuthScreenViewState createState() => _AuthScreenViewState();
}
  
class _AuthScreenViewState extends State {
  PageController pageController;
  int pageIndex = 0;
  
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    pageController = PageController();
  }
  
  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    pageController.dispose();
  }
  
  onPageChanged(int pageIndex) {
    setState(() {
      this.pageIndex = pageIndex;
    });
  }
  
  onTap(int pageIndex) {
    //pageController.jumpToPage(pageIndex);
    pageController.animateToPage(pageIndex,
        duration: Duration(milliseconds: 300), curve: Curves.easeInOut);
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: PageView(
        children: [
            
          //when pageIndex == 0
          LoginPage(), 
            
          //when pageIndex == 1
          RegisterPage()
                  ],
        controller: pageController,
        onPageChanged: onPageChanged,
      ),
      bottomNavigationBar: CupertinoTabBar(
        currentIndex: pageIndex,
        onTap: onTap,
        activeColor: Theme.of(context).primaryColor,
        items: [
          BottomNavigationBarItem(
              title: Text("Log-In"),
              icon: Icon(
                FontAwesomeIcons.signInAlt,
              )),
          BottomNavigationBarItem(
              title: Text("Register"),
              icon: Icon(
                FontAwesomeIcons.userPlus,
              )),
        ],
      ),
    );
  }
}

注册页面( ):

/lib/pages/register_page.dart

Dart

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_auth_example/services/authentication_service.dart';
import 'package:provider/provider.dart';
  
class RegisterPage extends StatefulWidget {
  @override
  _RegisterPageState createState() => _RegisterPageState();
}
  
class _RegisterPageState extends State {
    
  //To Toggle Password Text Visibility.
  bool _obscureText = true; 
  String _username, _email, _password;
    
  //For the loading state.
  bool _isSubmitting; 
  
  final _formKey = GlobalKey();
  final _scaffoldKey = GlobalKey();
  
  FirebaseAuth auth = FirebaseAuth.instance;
  final DateTime timestamp = DateTime.now();
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(title: Text("GeeksForGeeks"), centerTitle: true),
      body: Container(
        padding: EdgeInsets.symmetric(horizontal: 20),
        child: Center(
          child: SingleChildScrollView(
            child: Form(
              key: _formKey,
              child: Column(
                children: [
                  _showTitle(),
                  _showUsernameInput(),
                  _showEmailInput(),
                  _showPasswordInput(),
                  _showFormActions()
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
  
  //1
  _showTitle() {
    return Text(
      "Register",
      style: TextStyle(fontSize: 72, fontWeight: FontWeight.bold),
    );
  }
  
  //2
  _showUsernameInput() {
    return Padding(
      padding: EdgeInsets.only(top: 20),
      child: TextFormField(
        onSaved: (val) => _username = val,
        validator: (val) => val.length < 6 ? "Username is too short." : null,
        decoration: InputDecoration(
            border: OutlineInputBorder(),
            labelText: "Username",
            hintText: "Enter Valid Username",
            icon: Icon(
              Icons.face,
              color: Colors.grey,
            )),
      ),
    );
  }
  
  //3
  _showEmailInput() {
    return Padding(
      padding: EdgeInsets.only(top: 20),
      child: TextFormField(
        onSaved: (val) => _email = val,
        validator: (val) => !val.contains("@") ? "Invalid Email" : null,
        decoration: InputDecoration(
            border: OutlineInputBorder(),
            labelText: "Email",
            hintText: "Enter Valid Email",
            icon: Icon(
              Icons.mail,
              color: Colors.grey,
            )),
      ),
    );
  }
  
  //4
  _showPasswordInput() {
    return Padding(
      padding: EdgeInsets.only(top: 20),
      child: TextFormField(
        onSaved: (val) => _password = val,
        validator: (val) => val.length < 6 ? "Password Is Too Short" : null,
        obscureText: _obscureText,
        decoration: InputDecoration(
            suffixIcon: GestureDetector(
              onTap: () {
                setState(() {
                  _obscureText = !_obscureText;
                });
              },
              child:
                  Icon(_obscureText ? Icons.visibility_off : Icons.visibility),
            ),
            border: OutlineInputBorder(),
            labelText: "Password",
            hintText: "Enter Valid Password",
            icon: Icon(
              Icons.lock,
              color: Colors.grey,
            )),
      ),
    );
  }
  
  //5
  _showFormActions() {
    return Padding(
      padding: EdgeInsets.only(top: 20),
      child: Column(
        children: [
          _isSubmitting == true
              ? CircularProgressIndicator(
                  valueColor:
                      AlwaysStoppedAnimation(Theme.of(context).primaryColor),
                )
              : RaisedButton(
                  child: Text(
                    "Submit",
                    style: TextStyle(color: Colors.black, fontSize: 18),
                  ),
                  elevation: 8.0,
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.all(Radius.circular(10))),
                  color: Colors.orange,
                  onPressed: _submit),
        ],
      ),
    );
  }
  
  //6
  _submit() {
    final _form = _formKey.currentState;
    if (_form.validate()) {
      _form.save();
      //print("Email $_email, Password $_password, Username $_username");
      _registerUser();
    } else {
      print("Form is Invalid");
    }
  }
    
  //7
  _registerUser() async {
    setState(() {
      _isSubmitting = true;
    });
  
    final logMessage = await context
        .read()
        .signUp(email: _email, password: _password);
  
    logMessage == "Signed Up"
        ? _showSuccessSnack(logMessage)
        : _showErrorSnack(logMessage);
  
    print(logMessage);
  
    if (logMessage == "Signed Up") {
      createUserInFirestore();
    } else {
      setState(() {
        _isSubmitting = false;
      });
    }
  }
  
  //When User "Signed Up", success snack will display.
  _showSuccessSnack(String message) {
    final snackbar = SnackBar(
      backgroundColor: Colors.black,
      content: Text(
        "$message",
        style: TextStyle(color: Colors.green),
      ),
    );
    _scaffoldKey.currentState.showSnackBar(snackbar);
    _formKey.currentState.reset();
  }
  
  //When FirebaseAuth Catches error, error snack will display.
  _showErrorSnack(String message) {
    final snackbar = SnackBar(
      backgroundColor: Colors.black,
      content: Text(
        "$message",
        style: TextStyle(color: Colors.red),
      ),
    );
    _scaffoldKey.currentState.showSnackBar(snackbar);
  }
  
  createUserInFirestore() async {
    context.read().addUserToDB(
        uid: auth.currentUser.uid,
        username: _username,
        email: auth.currentUser.email,
        timestamp: timestamp);
  }
}

输出:

Flutter 和 Firebase:电子邮件/密码注册和登录(注册页面)

注册页面身份验证逻辑工作流。

登录页面( ):

LoginPageRegisterPage完全相似,唯一的区别是 LoginPage 只有两个 TextFormField(用于电子邮件和密码)并且在提交时触发 signIn() authentication_service 的方法。dart

/lib /pages/login_page.dart

Dart

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_auth_example/services/authentication_service.dart';
import 'package:provider/provider.dart';
  
class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}
  
class _LoginPageState extends State {
  bool _obscureText = true;
  String _email, _password;
  bool _isSubmitting;
  
  final _formKey = GlobalKey();
  final _scaffoldKey = GlobalKey();
  
  FirebaseAuth auth = FirebaseAuth.instance;
  final DateTime timestamp = DateTime.now();
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(
        centerTitle: true,
        title: Text("GeeksForGeeks"),
      ),
      body: Container(
        padding: EdgeInsets.symmetric(horizontal: 20),
        child: Center(
          child: SingleChildScrollView(
            child: Form(
              key: _formKey,
              child: Column(
                children: [
                  _showTitle(),
                  _showEmailInput(),
                  _showPasswordInput(),
                  _showFormActions()
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
  
  _showTitle() {
    return Text(
      "Login",
      style: TextStyle(fontSize: 72, fontWeight: FontWeight.bold),
    );
  }
  
  _showEmailInput() {
    return Padding(
      padding: EdgeInsets.only(top: 20),
      child: TextFormField(
        onSaved: (val) => _email = val,
        validator: (val) => !val.contains("@") ? "Invalid Email" : null,
        decoration: InputDecoration(
            border: OutlineInputBorder(),
            labelText: "Email",
            hintText: "Enter Valid Email",
            icon: Icon(
              Icons.mail,
              color: Colors.grey,
            )),
      ),
    );
  }
  
  _showPasswordInput() {
    return Padding(
      padding: EdgeInsets.only(top: 20),
      child: TextFormField(
        onSaved: (val) => _password = val,
        validator: (val) => val.length < 6 ? "Password Is Too Short" : null,
        obscureText: _obscureText,
        decoration: InputDecoration(
            suffixIcon: GestureDetector(
              onTap: () {
                setState(() {
                  _obscureText = !_obscureText;
                });
              },
              child:
                  Icon(_obscureText ? Icons.visibility_off : Icons.visibility),
            ),
            border: OutlineInputBorder(),
            labelText: "Password",
            hintText: "Enter Valid Password",
            icon: Icon(
              Icons.lock,
              color: Colors.grey,
            )),
      ),
    );
  }
  
  _showFormActions() {
    return Padding(
      padding: EdgeInsets.only(top: 20),
      child: Column(
        children: [
          _isSubmitting == true
              ? CircularProgressIndicator(
                  valueColor:
                      AlwaysStoppedAnimation(Theme.of(context).primaryColor),
                )
              : RaisedButton(
                  child: Text(
                    "Submit",
                    style: TextStyle(color: Colors.black, fontSize: 18),
                  ),
                  elevation: 8.0,
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.all(Radius.circular(10))),
                  color: Colors.orange,
                  onPressed: _submit),
        ],
      ),
    );
  }
  
  _submit() {
    final _form = _formKey.currentState;
    if (_form.validate()) {
      _form.save();
      //print("Email $_email, Password $_password");
      _LoginUser();
    } else {
      print("Form is Invalid");
    }
  }
  
  _LoginUser() async {
    setState(() {
      _isSubmitting = true;
    });
  
    final logMessage = await context
        .read()
        .signIn(email: _email, password: _password);
  
    logMessage == "Signed In"
        ? _showSuccessSnack(logMessage)
        : _showErrorSnack(logMessage);
  
    //print("I am logMessage $logMessage");
  
    if (logMessage == "Signed In") {
      return;
    } else {
      setState(() {
        _isSubmitting = false;
      });
    }
  }
  
  _showSuccessSnack(String message) async {
    final snackbar = SnackBar(
      backgroundColor: Colors.black,
      content: Text(
        "$message",
        style: TextStyle(color: Colors.green),
      ),
    );
    _scaffoldKey.currentState.showSnackBar(snackbar);
    _formKey.currentState.reset();
  }
  
  _showErrorSnack(String message) {
    final snackbar = SnackBar(
      backgroundColor: Colors.black,
      content: Text(
        "$message",
        style: TextStyle(color: Colors.red),
      ),
    );
    _scaffoldKey.currentState.showSnackBar(snackbar);
    setState(() {
      _isSubmitting = false;
    });
  }
}

输出:

登录页面身份验证逻辑工作流。

主页:

HomePage将在firebaseUser != null时显示,从main检查。dart

lib/pages/home_page.dart

Dart

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_auth_example/models/user_model.dart';
import 'package:flutter_auth_example/services/authentication_service.dart';
import 'package:provider/provider.dart';
  
class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}
  
class _HomePageState extends State {
  FirebaseAuth auth = FirebaseAuth.instance;
  final userRef = Firestore.instance.collection("users");
  UserModel _currentUser;
  
  String _uid;
  String _username;
  String _email;
  
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    getCurrentUser();
  }
  
  getCurrentUser() async {
    UserModel currentUser = await context
        .read()
        .getUserFromDB(uid: auth.currentUser.uid);
  
    _currentUser = currentUser;
  
    print("${_currentUser.username}");
  
    setState(() {
      _uid = _currentUser.uid;
      _username = _currentUser.username;
      _email = _currentUser.email;
    });
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("HomePage"),
        centerTitle: true,
      ),
      body: _currentUser == null
          ? Center(child: CircularProgressIndicator())
          : Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text(
                  "uid is ${_uid} , email is ${_email}, name is ${_username}",
                  textAlign: TextAlign.center,
                ),
                Center(
                  child: RaisedButton(
                    child: Text(
                      "Logout",
                      style: TextStyle(color: Colors.black, fontSize: 18),
                    ),
                    elevation: 8.0,
                    shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.all(Radius.circular(10))),
                    color: Colors.orange,
                    onPressed: () {
                      context.read().signOut();
                    },
                  ),
                ),
              ],
            ),
    );
  }
}

输出:

主页

最终输出:

想要一个更快节奏和更具竞争力的环境来学习 Android 的基础知识吗?
单击此处前往由我们的专家精心策划的指南,旨在让您立即做好行业准备!