当前位置: 首页 > news >正文

Flutter 基于google验证登录实现

注: 已实现登录Flutter端全部功能 基于
 

google_sign_in: ^7.1.1
#可选【如果找不到包的话 可以导入】
#  google_sign_in_web: ^1.0.0
#  google_sign_in_platform_interface: ^3.0.0

代码实现为

class AuthService extends GetxService{//从 Google Cloud Console 获取的后端 Web Client IDfinal String? _serverClientId = kIsWeb? null:'******.apps.googleusercontent.com';//Flutter Web Client ID,用于 Web 端的初始化final String? _webClientId = '******.apps.googleusercontent.com';String _errorMessage = '';// 根据平台选择不同的后端 URLfinal String AuthUrl = kIsWeb? "https://localhost/api/auth/google/": "https://localhost/api/auth/google/";final _storage = GsUtil.to;final GoogleSignIn _googleSignIn = GoogleSignIn.instance;GoogleSignIn get googleSignIn => _googleSignIn;@overridevoid onInit() async{await initialize();super.onInit();unawaited(_googleSignIn.initialize(clientId: _webClientId, serverClientId: _serverClientId).then((_) {_googleSignIn.authenticationEvents.listen(_handleAuthenticationEvent).onError(_handleAuthenticationEvent);/// This example always uses the stream-based approach to determining/// which UI state to show, rather than using the future returned here,/// if any, to conditionally skip directly to the signed-in state._googleSignIn.attemptLightweightAuthentication();}));}@overridevoid onClose(){super.onClose();}var isLoading = true.obs;// 初始化 GoogleSignIn 实例Future<void> initialize() async {try {await _googleSignIn.initialize(clientId: kIsWeb ? _webClientId : null,serverClientId: _serverClientId,);if(kIsWeb){final web.GoogleSignInPlugin _webPlugin = web.GoogleSignInPlugin();await _webPlugin.init(InitParameters(clientId: _webClientId,serverClientId: _serverClientId,),);}} catch (error) {debugPrint("Google Sign-In 初始化失败: $error");} finally {//无论成功或失败,最后都必须将 loading 状态设为 false**isLoading.value = false;}}// 触发登录流程Future<void> signIn() async {try {await _googleSignIn.authenticate();} catch (e) {debugPrint("authenticate error: $e");}}final List<String> scopes = <String>['email','profile', //可选 获取基础信息 头像 名称 等'https://www.googleapis.com/auth/user.phonenumbers.read', //可选 获取绑定手机号// 'https://www.googleapis.com/auth/contacts.readonly',];// 在获取到 user 对象后,调用此方法与后端通信/*** nickName 用户昵称* areaCode 电话区号* phone 手机号* vCode 邀请码*/String nickName="";String areaCode = "91";String phone = "";String vCode = "";Future<String?> exchangeCodeForToken(GoogleSignInAccount user) async {final LoadingController _loadingController = Get.find<LoadingController>();try {String serverAuthCode = "";_loadingController.show();// if(context.mounted) {//   DialogUtil.showLoadingDialog(context);// }// 关键步骤:请求服务器授权码try {final GoogleSignInServerAuthorization? serverAuth = await user.authorizationClient.authorizeServer(scopes);serverAuthCode = serverAuth == null ? '' : serverAuth.serverAuthCode;if (TextUtil.isEmpty(serverAuthCode)) {throw Exception("Failed to obtain Server Auth Code!");}} on GoogleSignInException catch (e) {_errorMessage = _errorMessageFromSignInException(e);}debugPrint("获取到 Server Auth Code,正在发送到后端...");final di = SpUtil.to?.readString(Config.deviceID);// 将 code 发送到 后端final response = await http.post(Uri.parse(AuthUrl),headers: {'Content-Type': 'application/json'},// Body 的 key 必须是 "code"body: jsonEncode({'code': serverAuthCode)}),);if (response.statusCode == 200) {final data = jsonDecode(response.body);final String jwtToken = data['access_token']; // 后端 返回的 keyawait _storage?.writeString("jwtToken", jwtToken);debugPrint("后端验证成功,已登录!");return jwtToken;} else {throw Exception("后端处理 code 失败: ${response.body}");}} catch (e) {debugPrint("exchangeCodeForToken error: $e");return null;}finally{_loadingController.hide();}}// 登出Future<void> signOut() async {await googleSignIn.disconnect();}//回调Future<void> _handleAuthenticationEvent(GoogleSignInAuthenticationEvent event) async {final GoogleSignInAccount? user = switch (event) {GoogleSignInAuthenticationEventSignIn() => event.user,GoogleSignInAuthenticationEventSignOut() => null,};final GoogleSignInClientAuthorization? authorization = await user?.authorizationClient.authorizationForScopes(scopes);if (user != null && authorization != null) {unawaited(exchangeCodeForToken(user));}}String _errorMessageFromSignInException(GoogleSignInException e) {return switch (e.code) {GoogleSignInExceptionCode.canceled => 'Sign in canceled',_ => 'GoogleSignInException ${e.code}: ${e.description}',};}//按钮逻辑Widget buildGoogleSignInButton() {if (kIsWeb) {return web_only.renderButton(configuration: web.GSIButtonConfiguration(type: web.GSIButtonType.icon,theme: web.GSIButtonTheme.outline,size: web.GSIButtonSize.large,text: web.GSIButtonText.continueWith,shape: web.GSIButtonShape.pill,// locale: ,minimumWidth: 45.0,// logoAlignment: web.GSIButtonLogoAlignment.left),);} else {// 移动端就用普通按钮if (GoogleSignIn.instance.supportsAuthenticate()){return GoogleSignInButton(onPressed: () async {if (Click.intervalClick(needTime: 2)) {await signIn();}},);}}return SizedBox(); // const Text('This platform does not have a known authentication method')}
}

以上就是核心工具类 踩了不少坑 自 github-google_sign 中抽取而出,都是精华
列位共勉

http://www.lryc.cn/news/618408.html

相关文章:

  • 肖臻《区块链技术与应用》第九讲:比特币交易的“智能”核心:深入解析脚本语言Script
  • Ubuntu系统安装学习笔记(Win双系统+非U盘安装)
  • AI智能体平台大爆发,2025AI智能体平台TOP30
  • ​​LangChain
  • 肖臻《区块链技术与应用》第十讲:深入解析硬分叉与软分叉
  • 云原生高级---TOMCAT
  • Json 中国全部省级、城市,数据来源于腾讯位置、城市选择器
  • 机器人焊接电源气体节气装置
  • GNSS接收机的工作原理及典型应用领域
  • Go面试题及详细答案120题(0-20)
  • vue3大事件
  • STL容器的使用时机
  • Jenkins 基本使用文档
  • SQL 生成日期与产品的所有组合:CROSS JOIN(笛卡尔积)
  • 「机器学习」:金融风控贷款违约预测,天池比赛解决详细思路
  • 超详细!VMware12 安装win7操作系统
  • Gartner 《IAM for LLM-Based AI Agents》学习心得
  • 从GPT-2到gpt-oss:架构演进分析
  • Git 常用命令速查表
  • Kafka的一条消息的写入和读取过程原理介绍
  • excel-随笔记
  • 基于Hadoop的农产品价格数据分析与可视化【Springboot】
  • 关于数据库的restful api接口工具SqlRest的使用
  • Next.js 中间件:自定义请求处理
  • 自动驾驶 HIL 测试:构建 “以假乱真” 的实时数据注入系统
  • 【Go】Gin 超时中间件的坑:fatal error: concurrent map writes
  • [java八股文][Mysql面试篇]架构
  • 虚拟机一站式部署Claude Code 可视化UI界面
  • 从裸机到云原生:Linux 操作系统实战进阶的“四维跃迁”
  • C++11-下