当已经在路由上时,如何使用 go_router 和 Firebase 身份验证处理 Flutter 中的身份验证?

dev*_*ock 8 firebase-authentication flutter gorouter flutter-navigation flutter-go-router

在我的 Flutter 应用程序中,我使用该go_router包来管理路由和Firebase Authentication用户身份验证。我有几个屏幕需要用户经过身份验证才能访问,例如帐户管理、交易和详细信息。

目前,我已经实现了重定向,go_router以确保未经身份验证的用户被正确重定向。但是,当用户已经位于这些屏幕之一并注销或会话过期时,我面临着挑战。

我正在考虑使用 BlocListener 来检测每个屏幕上身份验证状态的变化,但这似乎会导致代码重复。由于 Firebase 身份验证,我还有一个 Stream 通知身份验证状态的更改,并更新变量contex.isUserSignIn

使用 go_router 和 Firebase 身份验证有效处理 Flutter 中的注销或会话过期事件的最佳实践是什么?

小智 9

我\xe2\x80\x99一直在努力解决完全相同的问题,并研究了几种替代方案和选项。

\n

TL;DR: 选项 3 是我的首选,它使用该级别GoRouter.refresh()的方法main()根据 auth 流中的事件动态更新 GoRouter 状态。

\n

选项 1:遵循 go_router async_redirection.dart 示例

\n

请参阅此处的示例:https://github.com/flutter/packages/blob/main/packages/go_router/example/lib/async_redirection.dart

\n

这将顶层应用程序包装起来,通常MyApp(由main()in返回runApp())在 InheritedNotifer 小部件中,它们调用该小部件并在通知程序和 go_router 的解析管道StreamAuthScope之间创建依赖关系。当身份验证状态发生变化时(通过via进行通信) StreamAuthNotifier,这将依次重建MyApp(或App在示例中)。StreamAuthNotifiernotifyListeners()

\n

我基于 Provider 包实现了一个类似的模型,其中ChangeProviderNotifier替换StreamAuthScope并包装MyAppmain(). Provider.of<>然而,这不允许在机柜内创建受监控的\xe2\x80\x99 GoRouter( redirect: )。为了解决这个问题,我创建了一个getRouter传入的函数,该函数在函数主体中但在函数之前isUserSignIn通过 a 进行监视。这可行,但感觉很麻烦,并且\n导致每次身份验证状态更改时都需要重建主程序。如果需要,我\xe2\x80\x99m确信你可以用 BLoC 模型代替 Provider 做类似的事情。Provider.of<>MyAppbuildMyApp

\n

选项 2:使用GoRouter\xe2\x80\x99srefreshListenable:参数

\n

这是基于此 go_router redirection.dart 示例:https://github.com/flutter/packages/blob/main/packages/go_router/example/lib/redirection.dart

\n

在您提到的问题中,您有一个通知身份验证状态更改的流。您可以将其包装在一个类中以extends ChangeNotifier使其可监听。然后在构造函数中,您可以使用 实例化和监视流,并在每次身份验证状态更改时(可能每次有流事件时).listen在附件中发出 a 。notifyListerners()在我的例子中,我调用这个类,AuthNotifier然后可以将其用作可听的GoRouter\xe2\x80\x99srefreshListenable:参数,如下所示:refreshListenable: AuthNotifier()

\n

示例AuthNotifier

\n
class AuthNotifier extends ChangeNotifier {\n  AuthNotifier() {\n    // Continuously monitor for authStateChanges\n    // per: https://firebase.google.com/docs/auth/flutter/start#authstatechanges\n    _subscription =\n        FirebaseAuth.instance.authStateChanges().listen((User? user) {\n          // if user != null there is a user logged in, however\n          // we can just monitor for auth state change and notify\n          notifyListeners();\n        });\n  } // End AuthNotifier constructor\n\n  late final StreamSubscription<dynamic> _subscription;\n\n  @override\n  void dispose() {\n    _subscription.cancel();\n    super.dispose();\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

注意:为了避免创建和监视多个流,您需要确保此构造函数仅在您的应用程序中调用一次(在本例中作为GoRouter\xe2\x80\x99s的一部分refreshListenable:),或者将其修改为单例。

\n

选项 3:使用GoRouter\xe2\x80\x99s.refresh()方法

\n

与选项 2 类似但更直接的方法是使用GoRouter\xe2\x80\x99s.refresh()方法。notifyListerners()这直接调用刷新GoRouter配置的内部。我们可以使用与上面类似的类AuthNotifier,但我们不需要\xe2\x80\x99 extends ChangeNotifier,并且会调用router.refresh()来代替notifyListeners()router你的GoRouter()配置在哪里。这个新类将在 中实例化main()

\n

鉴于其如此简单(2-3行代码),我们也可以跳过类定义和实例化,直接在主体中实现功能main(),如下所示:

\n
Future<void> main() async {\n  WidgetsFlutterBinding.ensureInitialized();\n  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);\n\n  // Listen for Auth changes and .refresh the GoRouter [router]\n  FirebaseAuth.instance.authStateChanges().listen((User? user) {\n    router.refresh();\n  });\n\n  runApp(\n    const MyApp(),\n  );\n}\n
Run Code Online (Sandbox Code Playgroud)\n

由于这似乎是最直接、最简单的解决方案,因此它是我首选的解决方案,也是我已经实施的解决方案。然而,那里有很多令人困惑和过时的信息,我不\xe2\x80\x99觉得我有足够的经验来声称它是任何类型的“最佳实践”,所以将其留给其他人来判断和评论。

\n

我希望所有这些对您和其他人有所帮助,因为它\xe2\x80\x99s花了我很长时间来制定这些不同的选项,并涉足广泛的材料和选项。我觉得绝对有机会改进这方面的官方 go_router 文档!

\n