You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Go Router与Bloc实现认证:认证通过后无法跳转首页

问题分析与解决方案

核心问题

  1. 多Bloc实例冲突:你在GetIt注册了AuthBloc单例,但LoginScreen里又通过BlocProvider创建了新的AuthBloc实例,导致登录后的状态更新只在新实例中,AuthStream监听的单例实例状态未变化。
  2. GoRouter未监听状态变化:GoRouter的redirect逻辑默认只在路由导航时执行,未配置refreshListenable,所以认证状态变化时不会重新触发redirect。
  3. redirect逻辑错误:根路由的redirect无论认证状态如何都返回/login,未处理已认证的情况。

修复步骤

1. 统一AuthBloc实例

删除LoginScreen中BlocProvider的create方法,改用BlocProvider.value复用GetIt中的单例:

GoRoute(
  path: "login",
  builder: (context, state) {
    return BlocProvider.value(
      value: locator.get<AuthBloc>(),
      child: const LoginScreen(),
    );
  },
)

同时在main函数中提前初始化AuthBloc并触发启动事件:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  Setup();
  // 初始化单例AuthBloc并触发启动事件
  final authBloc = locator.get<AuthBloc>();
  authBloc.add(AuthStarted());

  HydratedBloc.storage = await HydratedStorage.build(
    storageDirectory: kIsWeb
        ? HydratedStorage.webStorageDirectory
        : await getTemporaryDirectory(),
  );
  runApp(const TedtrisApp());
}

2. 配置GoRouter的refreshListenable

让GoRouter监听AuthStream的变化,状态更新时自动重新执行redirect:

final _router = GoRouter(
  // 添加refreshListenable,监听认证状态变化
  refreshListenable: AuthStream(locator.get<AuthBloc>().stream),
  routes: [
    GoRoute(
      path: "/",
      redirect: (context, state) {
        final authStatus = AuthStreamScope.of(context).isSignedIn();
        // 根据状态跳转:已认证去首页,未认证去登录页
        return authStatus == AuthStatus.authenticated ? "/home" : "/login";
      },
      routes: [
        // login路由(已修改为复用单例)
      ]),
    GoRoute(
      path: "/home",
      builder: (context, state) {
        return const Scaffold(body: HomeScreen());
      },
    ),
  ],
);

3. 优化AuthStream(可选,避免重复依赖GetIt)

修改AuthStream直接持有AuthBloc引用,减少依赖耦合:

class AuthStream extends ChangeNotifier {
  late final StreamSubscription<dynamic> _subscription;
  final AuthBloc _authBloc;

  AuthStream(this._authBloc) {
    _subscription = _authBloc.stream.listen((_) => notifyListeners());
  }

  AuthStatus isSignedIn() => _authBloc.state.authStatus;

  @override
  void dispose() {
    _subscription.cancel();
    super.dispose();
  }
}

class AuthStreamScope extends InheritedNotifier<AuthStream> {
  AuthStreamScope({super.key, required super.child, required AuthBloc authBloc})
      : super(notifier: AuthStream(authBloc));
  
  static AuthStream of(BuildContext ctx) =
      ctx.dependOnInheritedWidgetOfExactType<AuthStreamScope>()!.notifier!;
}

然后在TedtrisApp中传入AuthBloc:

class _TedtrisAppState extends State<TedtrisApp> {
  final AuthBloc _authBloc = locator.get<AuthBloc>();

  @override
  Widget build(BuildContext context) {
    return AuthStreamScope(
      authBloc: _authBloc,
      child: MaterialApp.router(
        debugShowCheckedModeBanner: false,
        routerConfig: _router,
        theme: lightTheme,
      ),
    );
  }
}

内容的提问来源于stack exchange,提问作者Chan May Lan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 17:31:02