簡體   English   中英

Flutter 網絡 google_sign_in:如何檢索 refreshToken

[英]Flutter web google_sign_in: How to retrieve refreshToken

google_sign_in不返回refreshToken 有沒有辦法通過 Google 登錄並接收刷新令牌,該令牌可以發送到 API 以進一步訪問用戶數據?

刷新令牌也可以使用 serverAuthCode 獲得,此時它始終為空。 已經創建了多個問題來描述這個問題:

有沒有辦法通過 Google Sign In 進行身份驗證並接收 refreshToken 或 serverAuthCode?

Google Sign In 基於 oAuth2,您可以創建自己的流程實現。

這是可用於檢索 refreshToken 的谷歌登錄服務的代碼片段:

import 'dart:async';
import 'dart:html' as html;

import 'package:oauth2/oauth2.dart' as oauth2;

class GoogleSignInService {
  final authorizationEndpoint =
      Uri.parse('https://accounts.google.com/o/oauth2/v2/auth');
  final tokenEndpoint = Uri.parse('https://oauth2.googleapis.com/token');

  final String identifier;
  final String secret;
  final String baseUrl;
  final List<String> scopes;

  _SignInSession? _signInSession;

  Uri get redirectUrl => Uri.parse('$baseUrl/callback.html');

  GoogleSignInService({
    required this.identifier,
    required this.secret,
    required this.baseUrl,
    required this.scopes,
  }) {
    html.window.addEventListener('message', _eventListener);
  }

  void _eventListener(html.Event event) {
    _signInSession?.completeWithCode((event as html.MessageEvent).data);
  }

  Future<GoogleSignInUser?> signIn() async {
    if (_signInSession != null) {
      return null;
    }

    final grant = oauth2.AuthorizationCodeGrant(
      identifier,
      authorizationEndpoint,
      tokenEndpoint,
      secret: secret,
    );

    var authorizationUrl = grant.getAuthorizationUrl(
      redirectUrl,
      scopes: scopes,
    );

    final url =
        '${authorizationUrl.toString()}&access_type=offline&prompt=select_account+consent';
    _signInSession = _SignInSession(url);
    final code = await _signInSession!.codeCompleter.future;

    if (code != null) {
      final client = await grant.handleAuthorizationResponse({'code': code});
      return GoogleSignInUser(
        accessToken: client.credentials.accessToken,
        refreshToken: client.credentials.refreshToken,
        idToken: client.credentials.idToken!,
      );
    } else {
      return null;
    }
  }
}

class GoogleSignInUser {
  final String accessToken;
  final String? refreshToken;
  final String idToken;

  const GoogleSignInUser({
    required this.accessToken,
    required this.refreshToken,
    required this.idToken,
  });

  @override
  String toString() {
    return 'GoogleSignInUser{accessToken: $accessToken, refreshToken: $refreshToken, idToken: $idToken}';
  }
}

class _SignInSession {
  final codeCompleter = Completer<String?>();
  late final html.WindowBase _window;
  late final Timer _timer;

  bool get isClosed => codeCompleter.isCompleted;

  _SignInSession(String url) {
    _window =
        html.window.open(url, '_blank', 'location=yes,width=550,height=600');
    _timer = Timer.periodic(const Duration(milliseconds: 500), (timer) {
      if (_window.closed == true) {
        if (!isClosed) {
          codeCompleter.complete(null);
        }
        _timer.cancel();
      }
    });
  }

  void completeWithCode(String code) {
    if (!isClosed) {
      codeCompleter.complete(code);
    }
  }
}

確保還創建web/callback.html文件:

<html>
<body>
</body>
<script>
        function findGetParameter(parameterName) {
            var result = null,
            tmp = [];
            location.search
                .substr(1)
                .split("&")
                .forEach(function (item) {
                    tmp = item.split("=");
                    if (tmp[0] === parameterName) result = decodeURIComponent(tmp[1]);
                 });
            return result;
         }
        let code = findGetParameter('code');

        window.opener.postMessage(code, "http://localhost:5000");
        window.close();
    </script>
</html>

http://localhost:5000更改為您在生產中使用的任何域。

示例用法:

final googleSignIn = GoogleSignInService(
        identifier: 'CLIENT_ID',
        secret: 'CLIENT_SECRET',
        baseUrl: 'http://localhost:5000',
        scopes: [
          'email',
        ],
      ),
final user = await googleSignIn.signIn();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM