【问题标题】:Oauth2 Client & Open ID Connect in Flutter - Authorization Code Grant TypeFlutter 中的 Oauth2 Client & Open ID Connect - 授权码授予类型
【发布时间】:2021-12-14 20:28:30
【问题描述】:

所以大部分关于 Authorization 的教程只是使用 Firebase 的 Auth,并且大部分后端工作都得到了处理。

我需要在 Dart/Flutter 中为 Intuit 的 Quickbooks Online 创建一个 OAuth 客户端。

我的基本理解是当用户启动我的 Flutter Web 应用程序时,我会弹出一个屏幕来启动 Authorization Code Grant - OAuth。

他们使用此弹出屏幕登录 Intuit Quickbooks,然后授予我的应用程序权限。

此时我的应用程序应该会收到一个授权码。

我猜我需要将此授权码存储在我的 Google Cloud Firestore 中?

我需要将此授权码发送回 Intuit 并接收两件事:访问令牌和刷新令牌。

我想我也应该将这些存储在 Cloud Firestore 中?

但我看不出云功能在这张照片中的位置。我是否使用云函数向 Cloud Firestore 写入/读取?

如何处理用户会话?我还需要解决状态管理问题。

我开始明白为什么很多人只使用 Firebase Auth 的内置开箱即用功能,因为在 Dart/Flutter 中开发自定义 OAuth 客户端是一项艰巨的任务。

我开始感到困惑和迷茫。我需要一些建议或组织,因为我忽略了需要修改、设计或开发的内容。

Main.dart

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:html' as html;
import 'dart:convert';w
import 'package:cloud_firestore/cloud_firestore.dart';

Future main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(App());
}

class App extends StatefulWidget {
  // Create the initialization Future outside of `build`:
  @override
  _AppState createState() => _AppState();
}

class _AppState extends State<App> {
  final Future<FirebaseApp> _initialization = Firebase.initializeApp();

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      /// Initialize FlutterFire:
      future: _initialization,
      builder: (context, snapshot) {
        if (snapshot.hasError) {
          return Text(snapshot.error.toString());
        }

        /// Once complete, show your application
        if (snapshot.connectionState == ConnectionState.done) {
          return MyApp();
        }
        /// Otherwise, show something whilst waiting for initialization to complete
        return CircularProgressIndicator();
      },
    );
  }
}


/// Client id provided by Intuit, our production app ClientID
const String clientId = "ABS0R9arxiHjNcAb0rP7OMs8aS1FRiMIINxOkhQimUPewGmQ2H";
const String clientSecret = "";

class MyApp extends StatelessWidget {
  /// This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Title',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primaryColor: cPrimaryColor,

        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late String _token;
  late html.WindowBase _popupWin;

  Future<String> _validateToken() async {
    final response = await http.get(
      Uri.parse('https://appcenter.intuit.com/connect/oauth2'),
      headers: {'Authorization': 'OAuth $_token'},
    );
    return (jsonDecode(response.body) as Map<String, dynamic>)['login']
        .toString();
  }

  void _login(String data) {
    /// Parse data to extract the token.
    final receivedUri = Uri.parse(data);

    /// Close the popup window
    if (_popupWin != null) {
      _popupWin.close();
      _popupWin == null; // changed = to ==
    }

    setState(() => _token = receivedUri.fragment
        .split('&')
        .firstWhere((e) => e.startsWith('access_token='))
        .substring('access_token='.length));
  }

  @override
  void initState() {
    super.initState();

    /// Listen to message send with `postMessage`.
    html.window.onMessage.listen((event) {
      /// The event contains the token which means the user is connected.
      if (event.data.toString().contains('access_token=')) {
        _login(event.data);
      }
    });

    /// You are not connected so open the Intuit authentication page.
    WidgetsBinding.instance!.addPostFrameCallback((_) {
      final currentUri = Uri.base;
      final redirectUri = Uri(
        host: currentUri.host,
        scheme: currentUri.scheme,
        port: currentUri.port,
        path: '/static.html',
      );
      final authUrl = //TODO add state=security_token
          'https://appcenter.intuit.com/connect/oauth2?client_id=ABS0R9arxiHjNcAb0rP7OMs8aS1FRiMIINxOkhQimUPewGmQ2H&response_type=code&scope=com.intuit.quickbooks.accounting&redirect_uri=https://google.com/&state=security_token%3D138r5719ru3e1%26url%3Dhttps://qb-payment-app.web.app/';
      _popupWin = html.window.open(
          authUrl, "Intuit QuickBooks Online Auth", "width=800, height=900, scrollbars=yes");
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('My App Bar'),
      )
    );
  }
}

【问题讨论】:

    标签: firebase flutter dart google-cloud-firestore oauth-2.0


    【解决方案1】:

    你在这里问了很多问题。我将解决其中一个陈述:

    我开始明白为什么很多人只使用 Firebase Auth 的内置开箱即用功能,因为在 Dart/Flutter 中开发自定义 OAuth 客户端是一项艰巨的任务。

    实际上实现自定义 OAuth 客户端非常容易,请在我实现自己的 google 登录服务的地方查看这个问题:Flutter web google_sign_in: How to retrieve refreshToken

    您可以自定义此服务以使用 Quickbooks 而不是 Google SignIn。

    【讨论】:

    • 您在链接上提供的代码看起来对我来说将是一个非常有用的起点!无论出于何种原因,在 Dart/Flutter 中编写自定义 OAuth 客户端确实让我大吃一惊。尽管我已经阅读了很多关于该主题的教育和信息材料,但我对流程感到非常困惑。太感谢了。我会更深入地查看您发布的链接,并返回我可能遇到的任何问题。
    • 我的应用是web应用,由于dart:io依赖,无法使用Oauth2包,与Flutter Web不兼容。
    • 我也在 Flutter Web 应用程序中使用此服务。 oauth2 包兼容 Flutter Web:pub.dev/packages/oauth2
    • 我一定是误会了。谢谢你的澄清。
    猜你喜欢
    • 2018-05-26
    • 2021-04-24
    • 1970-01-01
    • 2018-11-04
    • 2019-01-09
    • 2020-05-05
    • 1970-01-01
    • 2018-01-12
    • 2019-12-31
    相关资源
    最近更新 更多