Flutter网页授权插件flutter_web_auth_2的使用

Flutter网页授权插件flutter_web_auth_2的使用

Flutter Web Auth 2 是一个用于在Flutter应用程序中进行第三方Web服务认证的插件,它支持OAuth2等认证流程。本文将详细介绍如何使用这个插件,并提供完整的示例代码。

添加依赖

首先,在pubspec.yaml文件中添加依赖:

dependencies:
  flutter_web_auth_2: ^4.0.0-alpha.0

使用方法

自定义站点认证

对于自定义站点认证,可以按照以下步骤操作:

import 'package:flutter_web_auth_2/flutter_web_auth_2.dart';

// 显示对话框给用户
final result = await FlutterWebAuth2.authenticate(
  url: "https://my-custom-app.com/connect",
  callbackUrlScheme: "my-custom-app"
);

// 从返回的URL中提取token
final token = Uri.parse(result).queryParameters['token'];

Google OAuth2认证

对于Google OAuth2认证,需要额外引入http库来处理访问令牌请求:

import 'package:flutter_web_auth_2/flutter_web_auth_2.dart';
import 'dart:convert' show jsonDecode;
import 'package:http/http.dart' as http;

// 应用特定变量
final googleClientId = 'XXXXXXXXXXXX-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com';
final callbackUrlScheme = 'com.googleusercontent.apps.XXXXXXXXXXXX-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

// 构建URL
final url = Uri.https('accounts.google.com', '/o/oauth2/v2/auth', {
  'response_type': 'code',
  'client_id': googleClientId,
  'redirect_uri': '$callbackUrlScheme:/',
  'scope': 'email',
});

// 显示对话框给用户
final result = await FlutterWebAuth2.authenticate(
  url: url.toString(),
  callbackUrlScheme: callbackUrlScheme
);

// 从返回的URL中提取授权码
final code = Uri.parse(result).queryParameters['code'];

// 构建访问令牌请求URL
final tokenUrl = Uri.https('www.googleapis.com', 'oauth2/v4/token');

// 使用授权码获取访问令牌
final response = await http.post(tokenUrl, body: {
  'client_id': googleClientId,
  'redirect_uri': '$callbackUrlScheme:/',
  'grant_type': 'authorization_code',
  'code': code,
});

// 从响应体中解析出访问令牌
final accessToken = jsonDecode(response.body)['access_token'] as String;

设置指南

根据不同的平台,设置可能会有所不同。

Android

AndroidManifest.xml中添加如下配置:

<manifest>
  <application>
    <activity
      android:name="com.linusu.flutter_web_auth_2.CallbackActivity"
      android:exported="true">
      <intent-filter android:label="flutter_web_auth_2">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="YOUR_CALLBACK_URL_SCHEME_HERE" />
      </intent-filter>
    </activity>
  </application>
</manifest>

请确保替换YOUR_CALLBACK_URL_SCHEME_HERE为实际的回调URL方案。

iOS

对于iOS,通常不需要特殊配置,除非你使用的是Universal Links,则应指定https作为callbackUrlScheme

Web

对于Web平台,需要创建一个HTML文件(例如auth.html),用于捕获回调URL并将其发送回应用:

<!DOCTYPE html>
<title>Authentication complete</title>
<p>Authentication is complete. If this does not happen automatically, please close the window.</p>
<script>
  function postAuthenticationMessage() {
    const message = {
      'flutter-web-auth-2': window.location.href
    };

    if (window.opener) {
      window.opener.postMessage(message, window.location.origin);
      window.close();
    } else if (window.parent && window.parent !== window) {
      window.parent.postMessage(message, window.location.origin);
    } else {
      localStorage.setItem('flutter-web-auth-2', window.location.href);
      window.close();
    }
  }

  postAuthenticationMessage();
</script>

Windows 和 Linux

useWebview设为false时,回调URL方案必须以http://localhost:{port}开头。默认情况下,useWebviewtrue,这时你需要遵循desktop_webview_window的指南。

完整示例代码

下面是一个完整的示例项目结构,包括服务器端和客户端代码:

main.dart

import 'dart:async';
import 'dart:io' show HttpServer;

import 'package:desktop_webview_window/desktop_webview_window.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_web_auth_2/flutter_web_auth_2.dart';

const _html = '''
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Grant Access to Flutter</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    html, body { margin: 0; padding: 0; }

    main {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      min-height: 100vh;
      font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;
    }

    #icon {
      font-size: 96pt;
    }

    #text {
      padding: 2em;
      max-width: 260px;
      text-align: center;
    }

    #button a {
      display: inline-block;
      padding: 6px 12px;
      color: white;
      border: 1px solid rgba(27,31,35,.2);
      border-radius: 3px;
      background-image: linear-gradient(-180deg, #34d058 0%, #22863a 90%);
      text-decoration: none;
      font-size: 14px;
      font-weight: 600;
    }

    #button a:active {
      background-color: #279f43;
      background-image: none;
    }
  </style>
</head>
<body>
  <main>
    <div id="icon">&#x1F3C7;</div>
    <div id="text">Press the button below to sign in using your localhost account.</div>
    <div id="button"><a href="CALLBACK_URL_HERE">Sign in</a></div>
  </main>
</body>
</html>
''';

void main(List<String> args) {
  if (runWebViewTitleBarWidget(args)) {
    return;
  }
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  MyAppState createState() => MyAppState();
}

class MyAppState extends State<MyApp> {
  String _status = '';

  @override
  void initState() {
    super.initState();
    if (!kIsWeb) {
      startServer();
    }
  }

  Future<void> startServer() async {
    final server = await HttpServer.bind('127.0.0.1', 43823);

    server.listen((req) async {
      setState(() {
        _status = 'Received request!';
      });

      req.response.headers.add('Content-Type', 'text/html');

      req.response.write(
        _html.replaceFirst(
          'CALLBACK_URL_HERE',
          'foobar://success?code=1337',
        ),
      );

      await req.response.close();
    });
  }

  Future<void> authenticate() async {
    setState(() {
      _status = '';
    });

    // 正常情况下,Web平台上不需要指定自定义URL。但是在这个例子中,我们直接跳转到认证页面,因为我们无法启动socket服务器...
    final url = kIsWeb ? '${Uri.base}auth.html' : 'http://127.0.0.1:43823/';

    try {
      final result = await FlutterWebAuth2.authenticate(
        url: url,
        callbackUrlScheme: 'foobar',
        options: const FlutterWebAuth2Options(
          timeout: 5, // 示例:5秒超时
          // 设置Android浏览器优先级
          // customTabsPackageOrder: ['com.android.chrome'],
        ),
      );
      setState(() {
        _status = 'Got result: $result';
      });
    } on PlatformException catch (e) {
      setState(() {
        _status = 'Got error: $e';
      });
    }
  }

  @override
  Widget build(BuildContext context) => MaterialApp(
        home: Scaffold(
          appBar: AppBar(
            title: const Text('Web Auth 2 example'),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text('Status: $_status\n'),
                const SizedBox(height: 80),
                ElevatedButton(
                  onPressed: () async {
                    await authenticate();
                  },
                  child: const Text('Authenticate'),
                ),
              ],
            ),
          ),
        ),
      );
}

通过以上步骤,你可以轻松地在Flutter应用中集成第三方Web服务认证功能。希望这篇文章对你有所帮助!如果有任何问题或建议,请随时留言。


更多关于Flutter网页授权插件flutter_web_auth_2的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter网页授权插件flutter_web_auth_2的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter应用中使用flutter_web_auth_2插件进行网页授权的示例代码。这个插件允许你在Flutter应用中启动一个Web浏览器视图来完成OAuth 2.0或OpenID Connect授权流程。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加flutter_web_auth_2依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_web_auth_2: ^0.10.0  # 请检查最新版本号

然后运行flutter pub get来安装依赖。

2. 配置Android和iOS

Android

确保在AndroidManifest.xml中添加了必要的Internet权限:

<uses-permission android:name="android.permission.INTERNET"/>

iOS

通常不需要额外的iOS配置,但确保你的Info.plist中有适当的网络权限设置(虽然对于OAuth通常不是必需的)。

3. 使用插件

下面是一个使用flutter_web_auth_2进行OAuth 2.0授权的示例代码:

import 'package:flutter/material.dart';
import 'package:flutter_web_auth_2/flutter_web_auth_2.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Web Auth Example'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: _authorize,
            child: Text('Authorize'),
          ),
        ),
      ),
    );
  }

  Future<void> _authorize() async {
    try {
      // 替换为你的授权URL和重定向URI
      final url = Uri.parse('https://example.com/oauth/authorize');
      final redirectUri = Uri.parse('com.example.app:/oauth2redirect');

      // 启动授权流程
      final result = await FlutterWebAuth.authenticate(
        url: url,
        callbackUrlScheme: 'com.example.app',
        // 可选参数,例如客户端ID和范围
        additionalParameters: {
          'client_id': 'your_client_id',
          'redirect_uri': redirectUri.toString(),
          'response_type': 'code',
          'scope': 'read write',
        },
      );

      // 处理授权结果
      if (result != null && result.isScheme('com.example.app')) {
        // 解析授权码
        final authCode = Uri.parse(result).queryParameters['code'];
        if (authCode != null) {
          // 使用授权码交换访问令牌
          // 这里你需要向你的认证服务器发送请求,通常是一个POST请求
          // 示例代码省略,因为这涉及到后端API调用
          print('Authorization Code: $authCode');
        }
      }
    } catch (e) {
      // 处理错误
      print('Authentication failed: $e');
    }
  }
}

注意事项

  1. 回调URL Scheme:确保你在Android的AndroidManifest.xml和iOS的Info.plist中注册了回调URL Scheme(如com.example.app)。这是插件用来检测回调并返回结果的方式。

  2. 安全性:确保你的重定向URI是安全的,并且只在你的应用中注册。避免使用像http://localhost这样的URI,因为它们可能不安全,并且可能无法在所有设备上正常工作。

  3. 错误处理:在实际应用中,添加更多的错误处理逻辑,以处理各种可能的失败情况,如网络错误、用户取消授权等。

  4. 访问令牌交换:上面的代码示例中省略了使用授权码交换访问令牌的步骤。这通常涉及向你的认证服务器发送一个POST请求,包含授权码、客户端ID、客户端秘密(如果适用)和重定向URI。

希望这个示例能帮助你在Flutter应用中使用flutter_web_auth_2插件进行网页授权!

回到顶部