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

Flutter中GoRouter结合Firebase Auth路由鉴权配置失败求助

解决GoRouter与Firebase Auth结合的完整鉴权流程

你的问题核心在于同步获取currentUser存在异步初始化时机问题,Web端Firebase Auth的用户状态加载是异步的,直接调用FirebaseAuth.instance.currentUser大概率返回null。必须通过监听authStateChanges流来实时同步登录状态,再结合GoRouter的动态刷新机制实现鉴权跳转。

一、重构AuthService类

用Firebase原生的authStateChanges流暴露登录状态,同时封装必要的登录/登出方法:

import 'package:firebase_auth/firebase_auth.dart';

class AuthService {
  final FirebaseAuth _auth = FirebaseAuth.instance;

  // 暴露登录状态流,供GoRouter监听
  Stream<User?> get authStateStream => _auth.authStateChanges();

  // 异步获取当前用户(处理初始化阶段的异步加载)
  Future<User?> getCurrentUser() async => _auth.currentUser;

  // 邮箱密码登录示例
  Future<UserCredential> signIn(String email, String password) async {
    return await _auth.signInWithEmailAndPassword(email: email, password: password);
  }

  // 登出
  Future<void> signOut() async => await _auth.signOut();
}

二、实现GoRouter的动态状态监听

自定义RefreshListenable将Firebase的状态流转换成GoRouter可识别的刷新触发器,确保登录状态变化时自动重新计算路由:

import 'package:go_router/go_router.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'auth_service.dart';

final AuthService _authService = AuthService();

// 路由常量
const String loginPath = '/login';
const String homePath = '/';
const String profilePath = '/profile';

final GoRouter router = GoRouter(
  // 监听auth状态流,状态变化时通知GoRouter刷新路由
  refreshListenable: _AuthRefreshStream(_authService.authStateStream),
  initialLocation: homePath,
  // 异步跳转逻辑,确保获取到最新登录状态
  redirect: (context, state) async {
    final User? user = await _authService.getCurrentUser();
    final bool isLoggedIn = user != null;

    // 未登录且不在登录页,跳转登录
    if (!isLoggedIn && state.location != loginPath) {
      return loginPath;
    }
    // 已登录且在登录页,跳转首页
    if (isLoggedIn && state.location == loginPath) {
      return homePath;
    }
    // 其他情况不跳转
    return null;
  },
  routes: [
    GoRoute(
      path: loginPath,
      builder: (context, state) => const LoginPage(), // 你的登录页面
    ),
    GoRoute(
      path: homePath,
      builder: (context, state) => const HomePage(), // 你的首页
      // 需登录才能访问的子路由示例
      routes: [
        GoRoute(
          path: 'profile',
          builder: (context, state) => const ProfilePage(), // 个人资料页
        ),
      ],
    ),
  ],
);

// 自定义刷新触发器,将Firebase流转换为GoRouter可监听对象
class _AuthRefreshStream extends ChangeNotifier {
  _AuthRefreshStream(Stream<User?> stream) {
    _subscription = stream.listen((_) => notifyListeners());
  }

  late final StreamSubscription<User?> _subscription;

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

三、初始化Firebase(Web端关键)

确保在应用启动时完成Firebase初始化,否则Auth状态无法正常加载:

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart'; // Firebase CLI生成的配置文件

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // 初始化Web端Firebase
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.web,
  );
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: router,
      title: 'Auth Demo',
    );
  }
}

关键注意事项

  1. 避免同步获取currentUser:Web端Firebase Auth初始化是异步的,同步调用FirebaseAuth.instance.currentUser会返回null,必须用异步方法或监听流。
  2. 测试登录状态:登录后可在Firebase控制台确认用户记录是否存在,排除登录本身的问题。
  3. 路由权限控制:所有需要登录的路由都不需要单独写判断,依赖顶层redirect逻辑即可统一控制。

内容的提问来源于stack exchange,提问作者Chris

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 12:01:11