Flutter 基于google验证登录实现

发布于:2025-08-17 ⋅ 阅读:(11) ⋅ 点赞:(0)

注: 已实现登录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 ID
  final String? _serverClientId = kIsWeb? null:'******.apps.googleusercontent.com';
  //Flutter Web Client ID,用于 Web 端的初始化
  final String? _webClientId = '******.apps.googleusercontent.com';
  String _errorMessage = '';
  // 根据平台选择不同的后端 URL
  final 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;
  @override
  void 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();
    }));
  }
  @override
  void 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']; // 后端 返回的 key
        await _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 中抽取而出,都是精华
列位共勉


网站公告

今日签到

点亮在社区的每一天
去签到