如何在 Riverpod 中管理 Firebase 身份验证?

问题描述

我有一个 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。我需要访问包含 firebaseAuthProviderFirebaseAuth.instance。要访问此提供程序,我需要在 HookWidget 内使用 useProvider 但这意味着将 ui 与逻辑混淆。我想在提供程序存在的同一个文件中将逻辑分开,即 firebase_providers.dart

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

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

解决方法

标准方法是创建一个接受 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 或其他数据提供者的存储库类。