ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Flutter Web 端 Google 登录实战指南:google_sign_in_web 的 GIS 集成、按钮渲染与令牌过期处理

Flutter Web 端 Google 登录实战指南:google_sign_in_web 的 GIS 集成、按钮渲染与令牌过期处理 Flutter Web 端 Google 登录实战指南google_sign_in_web 的 GIS 集成、按钮渲染与令牌过期处理【免费下载链接】packagesA collection of useful packages maintained by the Flutter team项目地址: https://gitcode.com/GitHub_Trending/pac/packages本文以 Flutter 官方维护的 google_sign_in_web 文档为主体讲解在 Flutter Web 应用中接入 Google 登录Google Sign-In的完整流程从 OAuth Client ID 创建、index.htmlmeta 标签配置、固定端口本地调试到基于 Google Identity ServicesGISSDK 的登录按钮渲染、认证/授权令牌管理及令牌过期后的处理策略。读完本文你将掌握 Web 端 Google 登录的正确接入姿势并理解该插件底层 GoogleSignInPlugin 的实现原理避免踩中“令牌一小时过期”“authenticate 不可用”等常见坑。一、插件定位被“背书”Endorsed的 Web 实现google_sign_in_web是 google_sign_in 的Web 平台实现属于 Flutter 官方联邦插件federated plugin体系。其 pubspec.yaml 中声明了flutter: plugin: implements: google_sign_in platforms: web: pluginClass: GoogleSignInPlugin fileName: google_sign_in_web.dartimplements: google_sign_in表示这是一个被“背书”endorsed的联邦插件当你仅依赖google_sign_in时Flutter 构建工具会根据当前目标平台自动引入本包无需在pubspec.yaml中显式添加google_sign_in_web。这也是官方文档反复强调的“直接使用google_sign_in即可”的原因。但有一个例外如果你需要直接调用本包暴露的 Web 专属 API例如登录按钮renderButton()就必须像普通依赖一样显式添加它dependencies: google_sign_in: ^7.0.0 google_sign_in_web: ^1.1.3 # 仅当直接 import 其 API 时需要从源码结构看Web 专属能力都集中在 lib/web_only.dart它导出renderButton以及GSIButtonConfiguration等按钮配置类型并在内部断言当前 GoogleSignInPlatform.instance 必须是GoogleSignInPluginWeb 实现防止在非 Web 环境误用。二、集成前准备创建 OAuth Client ID 与配置 Authorized JavaScript origins2.1 创建 OAuth 2.0 Web 客户端按官方指引在 Google Cloud Console 完成以下步骤获得形如xxxx.apps.googleusercontent.com的OAuth 2.0 Web application 客户端 ID进入 Google Cloud Console 的 API 凭据页面创建 OAuth 客户端 ID应用类型选择Web application记下生成的 Client ID用于下面的 meta 标签。2.2 在web/index.html中添加 meta 标签在你的 Flutter Web 项目的web/index.html中于head内添加以下 meta 标签meta namegoogle-signin-client_id contentYOUR_GOOGLE_SIGN_IN_OAUTH_CLIENT_ID.apps.googleusercontent.com插件启动时会自动读取该标签。见 google_sign_in_web.dartconst String clientIdMetaName google-signin-client_id; const String clientIdMetaSelector meta[name$clientIdMetaName]; const String clientIdAttributeName content; // 构造时自动查询 meta 标签 autoDetectedClientId web.document .querySelector(clientIdMetaSelector) ?.getAttribute(clientIdAttributeName);同时init() 中还有一条断言ClientID not set. Either set it on a meta namegoogle-signin-client_id contentCLIENT_ID / tag, or pass clientId when initializing GoogleSignIn。也就是说Client ID 有两种来源meta 标签或GoogleSignIn.initialize(clientId: ...)参数二者至少提供其一而serverClientId在 Web 端不支持assert(params.serverClientId null, ...)。2.3 配置 Authorized JavaScript originsClient ID 要能正常工作最后一步是在Credentials 页面编辑刚创建的 OAuth 2.0 Web 客户端进入 Google Cloud Console 的 Credentials 页面在你创建的 OAuth 2.0 Web application 客户端上点击Edit编辑在Authorized JavaScript origins已获授权的 JavaScript 来源中添加你想允许的域名。该配置用于“识别你的应用可以从哪些域发起 API 请求”。本地开发时必须添加两个localhost条目http://localhosthttp://localhost:7357或你机器上任意空闲端口2.4 固定端口启动 Flutter Web--web-port默认情况下flutter run会随机选择端口这对依赖回调域名白名单的 OAuth 流程很不友好。你需要让应用监听固定的 host 与端口flutter run -d chrome --web-hostname localhost --web-port 7357这样每次启动都固定为http://localhost:7357与上面配置的 Authorized JavaScript origins 完全对应。三、认证Authentication模型GIS SDK 与renderButton3.1 为什么authenticate()在 Web 上不可用该实现中supportsAuthenticate()返回false调用authenticate会直接抛出异常。原因是Google Identity Services (GIS) SDK 只允许使用 SDK 自身提供的 UI 进行登录不允许应用自绘 UI 再调起登录。对应实现见 google_sign_in_web.dartoverride bool supportsAuthenticate() false; override FutureAuthenticationResults authenticate(AuthenticateParameters params) async { throw UnimplementedError( authenticate is not supported on the web. Instead, use renderButton to create a sign-in widget., ); }因此 Web 端的正确做法是用renderButton()渲染 GIS 登录按钮并通过authenticationEvents流监听用户登录结果。3.2 用renderButton()渲染登录按钮renderButton定义在 web_only.dartWidget renderButton({GSIButtonConfiguration? configuration}) { return _plugin.renderButton(configuration: configuration); }由于它属于 Web 专属 API需要在pubspec.yaml中显式添加google_sign_in_web。官方示例 main.dart 展示了如何优雅地做平台分流if (GoogleSignIn.instance.supportsAuthenticate()) ElevatedButton( onPressed: () async { try { await GoogleSignIn.instance.authenticate(); } catch (e) { // ··· } }, child: const Text(SIGN IN), ) else ...Widget[ if (kIsWeb) web.renderButton() // ··· ],其中web是通过条件导入conditional import包装的Web 端使用 web_wrapper_web.dartexport package:google_sign_in_web/web_only.dart;其他平台则使用抛出StateError的 web_wrapper_stub.dart 桩实现从而保证非 Web 平台编译不引入 Web 依赖。renderButton的底层实现google_sign_in_web.dart依赖_initializedFuture插件初始化完成后通过ui_web.platformViewRegistry.registerViewFactory(gsi_login_button, ...)注册的 HTML 平台视图见 _registerButtonFactory承载 GIS 按钮初始化未完成时先显示Text(Getting ready)占位。3.3 按钮外观配置GSIButtonConfiguration 全参数renderButton支持传入 GSIButtonConfiguration可配置项与默认语义如下表最终通过convertButtonConfiguration映射为 GIS SDK 的GsiButtonConfiguration参数类型可选值说明typeGSIButtonTypestandard、icon标准按钮含文字/个性化信息或纯图标按钮themeGSIButtonThemeoutline、filledBlue、filledBlack描边白底、蓝色填充、黑色填充sizeGSIButtonSizelarge约 40px 高、medium约 32px、small约 20px按钮尺寸textGSIButtonTextsigninWith、signupWith、continueWith、signin按钮文案对应 “Sign in with Google” 等shapeGSIButtonShaperectangular、pill矩形或胶囊形logoAlignmentGSIButtonLogoAlignmentleft、centerGoogle 标志对齐仅对标准按钮生效默认leftminimumWidthdouble? 0按钮最小宽度像素构造时有assert(minimumWidth null \|\| minimumWidth 0)最大 400 像素localeString?预置区域字符串按钮文字的语言不设置时使用浏览器默认语言或 Google 会话用户偏好示例用法import package:google_sign_in_web/web_only.dart; Widget build(BuildContext context) { return renderButton( configuration: GSIButtonConfiguration( type: GSIButtonType.standard, theme: GSIButtonTheme.filledBlue, size: GSIButtonSize.large, text: GSIButtonText.signinWith, shape: GSIButtonShape.rectangular, minimumWidth: 240, ), ); }3.4 监听认证事件authenticationEvents登录状态通过authenticationEvents流google_sign_in_web.dart#L230对外发布。底层 GisSdkClient 会将 GIS SDK 的CredentialResponse经gisResponsesToAuthenticationEvent转换后推入流中gis_client.dart#L55-L63OneTap 卡片被取消、弹出框被关闭等情况则映射为GoogleSignInException如canceled、uiUnavailable、clientConfigurationError最终包装为AuthenticationEventException事件gis_client.dart#L342-L359。在google_sign_in层面监听signIn.authenticationEvents .listen(_handleAuthenticationEvent) .onError(_handleAuthenticationError);3.5 GIS SDK 不会续期3600 秒的令牌生命周期GIS SDK 不管理、也不续期用户会话。登录凭证idToken在3600 秒1 小时后过期之后若还需使用idToken必须重新触发一次认证流程。因此绝大多数场景下的推荐实践是认证后立即使用idToken登录状态在应用层自行跟踪如保存在本地状态管理中或交由独立的后端服务维护会话后端用idToken换取自己的会话。3.6 从 0.12 之前版本迁移旧版本插件使用的是 Google Sign-In旧 SDK与 GIS SDK 的认证模型差异较大。0.12 之后迁移要点GIS SDK不再管理用户会话依赖“长会话”的旧应用可能因此失效若需要长期会话建议改用支持 Google 作为联邦认证提供方的用户认证系统例如 Firebase Auth将 Google 登录委托给该类系统托管会话。四、授权Authorization模型Scopes、TokenClient 与过期处理4.1 检查已授予的 Scopes若用户此前已授权过应用所需 scopes可以静默获取 access token无需交互const ListString scopes String[https://www.googleapis.com/auth/contacts.readonly]; final GoogleSignInAccount? user // ... final GoogleSignInClientAuthorization? authorization await user?.authorizationClient .authorizationForScopes(scopes);4.2 请求更多 Scopes必须由用户交互触发当应用发现用户未授予所需 scopes 时应发起授权请求。在 Web 上authorizationRequiresUserInteraction()返回truegoogle_sign_in_web.dart#L155因此该请求必须由用户交互如按钮点击触发final GoogleSignInClientAuthorization authorization await user.authorizationClient .authorizeScopes(scopes);4.3 授权令牌同样不续期401 / 403 处理与认证一致GIS SDK 不会续期授权会话。access token 在 3600 秒后过期届时 API 请求会开始失败必须重新请求用户授权。典型错误表现401缺少或无效的 access token403access token 已过期。最佳实践是将 REST 请求的失败响应与上面描述的授权方法结合——捕获401/403后引导用户重新完成授权流程。从实现看Web 的 scopes 请求走 GIS SDK 的oauth2.TokenClientgis_client.dart#L118-L138并带有按用户缓存的令牌表requestScopes会优先返回未过期且已覆盖全部请求 scopes 的缓存令牌否则在允许提示时才拉起授权gis_client.dart#L280-L340。另外注意 scopes 中不能包含空格底层以空格分隔 scope 列表源码中有对应断言google_sign_in_web.dart#L211-L221。4.4 请求 Server Auth Code后端换取令牌若应用需要由后端服务器访问用户数据可以请求 server auth code 交给服务器final GoogleSignInServerAuthorization? serverAuth await user.authorizationClient .authorizeServer(scopes);Server auth code 并非在所有平台、所有时机都可用某些平台只在首次登录时返回。因此应在首次登录后尽快请求并让服务器侧全权维护该用户的令牌除非登录用户发生变化。Web 端该请求走oauth2.CodeClientpopup 模式gis_client.dart#L141-L160同样由于authorizationRequiresUserInteraction()为 true也必须由用户交互触发。4.5 登出与断开signOut()撤销当前认证禁用自动选择并发布AuthenticationEventSignOut事件disconnect()撤销所有缓存的授权令牌并登出遍历令牌缓存逐项调用oauth2.revoke。两者实现在 gis_client.dart#L252-L266。五、从 0.12 之前版本迁移认证与授权的双重差异文档强调两个迁移入口分属认证与授权两条线认证迁移对照 GIS SDK 与旧版 SDK 的认证差异说明授权迁移对照 GIS OAuth 2.0 Web 迁移指南核心变化同样是“SDK 不再管理会话、令牌不再自动续期”。无论认证还是授权核心结论一致旧的“长会话 自动续期”假设在 Web 端已不成立应用必须自己应对令牌过期重新认证/重新授权或将会话托管给 Firebase Auth 之类的联邦认证服务。六、测试与源码验证本包的单元测试位于仓库的共享测试目录test/README.md 说明了测试位于独立仓库的测试仓库中tests_exist_elsewhere_test.dart 作为占位测试而插件本身为可测试性做了充分设计GoogleSignInPlugin构造函数支持debugOverrideLoader跳过 JS SDK 加载、debugOverrideGisSdkClient替换 GIS SDK 客户端实现与debugAuthenticationController注入认证事件流三个visibleForTesting参数google_sign_in_web.dart#L47-L65GisSdkClient同样被设计为可覆写便于在 Dart 侧模拟 GIS SDK 行为而不依赖真实浏览器。七、快速上手指南汇总将以上要点浓缩为 Web 端接入google_sign_in的最小步骤创建 Client ID在 Google Cloud Console 创建 OAuth 2.0 Web application 客户端记录 Client ID配置 meta 标签在web/index.html的head中加入meta namegoogle-signin-client_id content你的ClientID.apps.googleusercontent.com配置授权来源在 Credentials 页面为该客户端添加 Authorized JavaScript origins本地开发至少包含http://localhost与http://localhost:7357固定端口运行flutter run -d chrome --web-hostname localhost --web-port 7357初始化并监听GoogleSignIn.instance.initialize(...)后监听authenticationEvents必要时调用attemptLightweightAuthentication()尝试静默登录渲染登录按钮显式添加google_sign_in_web依赖在kIsWeb分支调用web.renderButton(configuration: ...)该 API 来自 web_only.dart处理令牌过期认证/授权令牌均约 3600 秒过期认证后立即使用idToken遇到401/403时重新发起授权会话状态由应用层或后端服务自行维护。遵循以上流程即可在 Flutter Web 应用中稳定集成基于 GIS SDK 的 Google 登录并正确应对“无自定义 UI、无自动续期”两大 Web 端特性约束。【免费下载链接】packagesA collection of useful packages maintained by the Flutter team项目地址: https://gitcode.com/GitHub_Trending/pac/packages创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表