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

Flutter Web集成Firebase:谷歌登录后Google Calendar客户端为null的问题

问题描述

我使用Flutter开发Web应用,希望通过Google认证用户后获取其Google Calendar中的事件,同时集成了Firebase Authentication,已完成云控制台的所有配置。登录跳转代码如下:

Future<void> attemptSilentSignIn({bool andRedirect = true}) async {
  try {
    final GoogleSignInAccount? googleUser = await googleSignIn.signInSilently();
    if (googleUser != null) {
      final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
      final AuthCredential credential = GoogleAuthProvider.credential(
        accessToken: googleAuth.accessToken,
        idToken: googleAuth.idToken,
      );
      await FirebaseAuth.instance.signInWithCredential(credential);

      if (andRedirect) {
        Get.offAllNamed(Routes.calendario);
      }
    }
  } catch (error) {
    logger.e('Errore nel login silenzioso: $error');
  }
}

用户成功进入日历页面后,调用_fetchEventi方法获取日历事件时失败,提示authenticated client为null:

Future _fetchEventi() async {
  logger.i('Getting events from Google Calendar...');
  try {
    // Retrieve an [auth.AuthClient] from the current [GoogleSignIn] instance.
    final AuthClient? client = await _ac.googleSignIn.authenticatedClient();

    if (client == null) {
      throw GoogleException('Authenticated client missing!');
    }

    // ...

    final CalendarApi calendarApi = CalendarApi(client);
    final Events response = await calendarApi.events.list(
      'primary',
      timeMin: timeMin,
      timeMax: timeMax,
    );

    return response.items;
  } on GoogleException catch (_) {
    logger.e('Google Exception');
  } catch (e) {
    logger.e(e);
  }
}

该方法始终抛出自定义GoogleException。

补充说明:我发现authenticatedClient扩展方法会检查是否存在accessToken,但文档表明这是支持Web的插件,为何在Web平台上该方法始终返回null?

原因分析与解决方案

核心原因

Web平台下,google_sign_in插件的authenticatedClient()方法依赖带有Google Calendar API权限的有效accessToken,当前登录流程存在两个关键问题:

  1. 静默登录signInSilently()在Web端无法触发权限授权弹窗,即便云控制台配置了Calendar API范围,也不会自动获取对应权限的accessToken。
  2. 仅通过Firebase Auth完成登录,并没有让GoogleSignIn实例持有包含Calendar权限的accessToken,导致authenticatedClient()返回null。

具体解决步骤

  1. 初始化GoogleSignIn时指定Calendar API权限范围
    确保初始化GoogleSignIn时添加Calendar API的权限,示例:

    final GoogleSignIn googleSignIn = GoogleSignIn(
      scopes: [
        'email',
        'https://www.googleapis.com/auth/calendar.readonly', // 按需选择只读/读写权限
      ],
    );
    
  2. 替换静默登录为“静默优先+显式授权”的流程
    Web端signInSilently()无法触发权限授权,因此需要在静默登录失败时调用signIn()触发授权弹窗,获取带Calendar权限的accessToken:

    Future<void> attemptSignIn({bool andRedirect = true}) async {
      try {
        GoogleSignInAccount? googleUser = await googleSignIn.signInSilently();
        // 静默登录失败则触发显式登录授权
        if (googleUser == null) {
          googleUser = await googleSignIn.signIn();
        }
        if (googleUser != null) {
          final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
          final AuthCredential credential = GoogleAuthProvider.credential(
            accessToken: googleAuth.accessToken,
            idToken: googleAuth.idToken,
          );
          await FirebaseAuth.instance.signInWithCredential(credential);
    
          if (andRedirect) {
            Get.offAllNamed(Routes.calendario);
          }
        }
      } catch (error) {
        logger.e('登录错误: $error');
      }
    }
    
  3. 提前验证accessToken有效性
    在调用authenticatedClient()前,检查当前用户的accessToken是否存在,若不存在则重新触发授权:

    final GoogleSignInAccount? currentUser = _ac.googleSignIn.currentUser;
    if (currentUser != null) {
      final auth = await currentUser.authentication;
      if (auth.accessToken == null) {
        await _ac.googleSignIn.signIn();
      }
    }
    final AuthClient? client = await _ac.googleSignIn.authenticatedClient();
    
  4. 核对云控制台配置

    • 确认OAuth 2.0 Web客户端的授权域名包含你的Web应用域名。
    • 已在云控制台启用Google Calendar API。
    • OAuth consent screen中已添加Calendar API权限到已授权范围。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 05:22:17