【问题标题】:How to manage Firebase Authentication in Riverpod?如何在 Riverpod 中管理 Firebase 身份验证?
【发布时间】:2021-04-27 11:25:02
【问题描述】:

我有一个firebase_providers.dart 文件,如下所示:

import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:firebase_auth/firebase_auth.dart';

final firebaseAuthProvider = Provider((ref) => FirebaseAuth.instance);

final authStateChangesProvider = StreamProvider.autoDispose<User?>((ref) {
  return ref.watch(firebaseAuthProvider).authStateChanges();
});

它创建了 2 个简单的提供程序 - 一个用于 Firebase Auth 实例,另一个用于获取当前用户状态。我在我的主页上使用它是这样的:

class NavigationManager extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final user = useProvider(authStateChangesProvider);
    return user.when(
      loading: () => CircularProgressIndicator(),
      error: (error, stack) => Text('Error occured'),
      data: (user) {
        if (user == null) return LoginPage();
        return Dashboard();
      },
    );
  }
}

这是我根据用户身份验证状态更改页面的基本设置。

LoginPage 是一个有状态的小部件,它包含文本字段、控制器等。在这个文件中,我在userEmailuserPassword 中有用户电子邮件和密码,现在如何使用它来登录用户? Firebase Auth 的官方文档使用此代码:

UserCredential userCredential = await FirebaseAuth.instance.signInWithEmailAndPassword(
    email: "barry.allen@example.com",
    password: "SuperSecretPassword!"
);

我也可以这样做,但不会涉及 Riverpod。我需要访问包含FirebaseAuth.instancefirebaseAuthProvider。要访问此提供程序,我需要在HookWidget 内才能使用useProvider,但这意味着用户界面与逻辑混乱。我想将逻辑分开保存在提供者所在的同一个文件中,即firebase_providers.dart

我也想过做这样的事情 - 将 LoginPage 有状态小部件转换为 HookWidget,然后访问 firebaseAuthProvider 并使用它来调用可以驻留在 firebase_providers.dart 中的登录函数,但是我将如何管理我首先为其创建有状态小部件的表单和文本字段?

那么使用 Riverpod 管理和调用所有这些身份验证功能(如登录、注册等)的方法是什么?

【问题讨论】:

    标签: flutter dart firebase-authentication riverpod


    【解决方案1】:

    标准方法是创建一个接受ScopedReader 作为参数的服务类。

    例如:

    class AuthService {
      const AuthService(this._read);
    
      final Reader _read;
    
      static final provider = Provider((ref) => AuthService(ref.read));
    
      Future<void> emailSignIn(String email, String password) async {
        final auth = _read(firebaseAuthProvider);
        final credential = await auth.signInWithEmailAndPassword(email: email, password: password);
        // etc.
      }
    }
    

    然后在您的登录页面中:

    class LoginPage extends HookWidget {
      const LoginPage({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return ElevatedButton(
          onPressed: () async => context.read(AuthService.provider).emailSignIn(
                'barry.allen@example.com',
                'SuperSecretPassword!',
              ),
          child: Text('Login'),
        );
      }
    }
    

    同样的模式可以应用于使用 Firestore 或其他数据提供者的存储库类。

    【讨论】:

    • AuthService中的ref.read是什么意思?
    • ref.read 的行为类似于 ref.watch,只是它在用于读取提供程序时不观察重建。它是一个 ScopedReader,就像context.read。将它作为参数传递给 AuthService 允许您在没有上下文的情况下读取提供程序。
    猜你喜欢
    • 1970-01-01
    • 2018-12-05
    • 1970-01-01
    • 2013-07-10
    • 1970-01-01
    • 1970-01-01
    • 2021-09-19
    • 1970-01-01
    • 2018-07-23
    相关资源
    最近更新 更多