Flutter前端管理与安全插件frontegg_flutter的使用

发布于 1周前 作者 ionicwang 来自 Flutter

Flutter前端管理与安全插件frontegg_flutter的使用

Frontegg 是一个全栈用户管理平台,为软件团队提供了产品时代所需的基础功能。

目录

项目需求

  • 最低iOS部署版本 => 14
  • 最低Android SDK版本 => 26

开始使用

准备Frontegg工作区

导航至 Frontegg Portal Settings,如果还没有应用程序,请按照集成步骤操作。 从 Frontegg Portal Domain 复制Frontegg域名。

  • 导航至 登录方法设置
  • 为iOS切换托管登录方式:
    • 添加 {{IOS_BUNDLE_IDENTIFIER}}://{{FRONTEGG_BASE_URL}}/ios/oauth/callback
  • 为Android切换托管登录方式:
    • 添加 {{ANDROID_PACKAGE_NAME}}://{{FRONTEGG_BASE_URL}}/android/oauth/callback
    • 添加 https://{{FRONTEGG_BASE_URL}}/oauth/account/redirect/android/{{ANDROID_PACKAGE_NAME}}
  • 添加 {{FRONTEGG_BASE_URL}}/oauth/authorize
  • IOS_BUNDLE_IDENTIFIER 替换为您的应用程序标识符
  • FRONTEGG_BASE_URL 替换为您frontegg的基本URL
  • ANDROID_PACKAGE_NAME 替换为您的Android包名

将frontegg包添加到项目中

使用包管理器 pub 安装frontegg Flutter库。

终端:

dart pub add frontegg_flutter

或手动:

dependencies:
  frontegg_flutter: ^1.0.0

设置iOS项目

创建Frontegg plist文件

为了使您的SwiftUI应用程序能够与Frontegg通信,您需要在iOS项目目录下(例如ios/Runner)创建一个名为 Frontegg.plist 的新文件,并将其包含在XCode项目中。此文件将存储Frontegg SDK使用的变量值:

如何创建:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>baseUrl</key>
        <string>https://[DOMAIN_HOST_FROM_PREVIOUS_STEP]</string>
        <key>clientId</key>
        <string>[CLIENT_ID_FROM_PREVIOUS_STEP]</string>
    </dict>
</plist>

处理通过URL打开应用

对于Objective-C:
  1. 在项目中创建 FronteggSwiftAdapter.swift 并添加以下代码:
// FronteggSwiftAdapter.swift
import Foundation
import FronteggSwift

@objc(FronteggSwiftAdapter)
public class FronteggSwiftAdapter: NSObject {
    @objc public static let shared = FronteggSwiftAdapter()

    @objc public func handleOpenUrl(_ url: URL) -> Bool {
        return FronteggAuth.shared.handleOpenUrl(url)
    }
}
  1. 打开 AppDelegate.m 文件并导入Swift头文件:
#import "<YOUR_PROJECT_NAME>-Swift.h"
  1. AppDelegate.m 添加URL处理器:
#import "<YOUR_PROJECT_NAME>-Swift.h"

// ...CODE...

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url
        options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
{
     
  if([[FronteggSwiftAdapter shared] handleOpenUrl:url] ){
    return TRUE;
  }
  return [RCTLinkingManager application:app openURL:url options:options];
}
   
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity
 restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
{
     
  if (userActivity.webpageURL != NULL){
    if([[FronteggSwiftAdapter shared] handleOpenUrl:userActivity.webpageURL] ){
      return TRUE;
    }
  }
 return [RCTLinkingManager application:application
                  continueUserActivity:userActivity
                    restorationHandler:restorationHandler];
}
对于Swift:
  1. AppDelegate.swift 添加URL处理器:
import UIKit
import Flutter
import FronteggSwift

@main
@objc class AppDelegate: FlutterAppDelegate {
   
    /*
     * 当应用程序使用URL启动时调用。您可以在此处添加额外的处理逻辑,
     * 但如果您希望App API支持跟踪应用URL打开,请保留此调用。
     */
    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
           
        if(FronteggAuth.shared.handleOpenUrl(url, true)){
            return true
        }
           
        return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
    }
       
    /*
     * 当应用程序使用活动(包括通用链接)启动时调用。
     * 您可以在此处添加额外的处理逻辑,但如果您希望App API支持
     * 跟踪应用URL打开,请保留此调用。
     */
    func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
           
        if let url = userActivity.webpageURL {
            if(FronteggAuth.shared.handleOpenUrl(url, true)){
                return true
            }
        }
        return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
    }
}

配置iOS关联域

配置您的iOS关联域是为了实现魔法链接认证、重置密码、激活账户等功能。

为了向您的Frontegg应用添加iOS关联域,您需要更新每个集成的Frontegg环境中您想要使用的iOS关联域。发送POST请求到 https://api.frontegg.com/vendors/resources/associated-domains/v1/ios 并附带以下有效负载:

{
    “appId”:[YOUR_ASSOCIATED_DOMAIN]
}

接下来,您需要向您的iOS应用程序添加关联域。要执行此操作,请遵循以下步骤:

  1. 在Xcode中打开您的项目。
  2. 在项目导航器中选择您的项目。
  3. 选择您的目标。
  4. 选择“签名和能力”选项卡。
  5. 展开“关联域”部分。
  6. 点击+按钮。
  7. 输入您的关联域,格式为 applinks:[YOUR_ASSOCIATED_DOMAIN]
  8. 输入您的关联域,格式为 webcredentials:[YOUR_ASSOCIATED_DOMAIN]
  9. 点击完成。

多应用iOS支持

本指南概述了配置iOS应用以支持多个应用的步骤。

步骤1:修改Frontegg.plist文件

向Frontegg.plist文件中添加 applicationId

<plist version="1.0">
  <dict>
    <key>applicationId</key>
    <string>your-application-id-uuid</string>
    <key>baseUrl</key>
    <string>https://your-domain.fronteg.com</string>
    <key>clientId</key>
    <string>your-client-id-uuid</string>
  </dict>
</plist>

卸载应用后注销用户

如果您希望用户在重新安装应用后不保持登录状态,请向 Frontegg.plist 文件中添加 keepUserLoggedInAfterReinstall 属性:

<plist version="1.0">
  <dict>
    <key>keepUserLoggedInAfterReinstall</key>
    <false/>
    ...
  </dict>
</plist>

默认情况下,keepUserLoggedInAfterReinstalltrue

设置Android项目

设置最低SDK版本

为了设置您的Android最低SDK版本,请打开根级gradle文件 android/build.gradle,并在 buildscript.ext 下添加或编辑 minSdkVersion

buildscript {
    ext {
        minSdkVersion = 26
        // ...
    }
}

配置构建配置字段

为了使您的Android应用能够与Frontegg通信,您需要在gradle android/app/build.gradle 中添加 buildConfigField 属性。此属性将存储frontegg主机名(不包括协议https)和来自上一步的客户端ID:

def fronteggDomain = "FRONTEGG_DOMAIN_HOST.com" // 不包括协议 https://
def fronteggClientId = "FRONTEGG_CLIENT_ID"

android {
    defaultConfig {

        manifestPlaceholders = [
                "package_name" : applicationId,
                "frontegg_domain" : fronteggDomain,
                "frontegg_client_id": fronteggClientId
        ]

        buildConfigField "String", 'FRONTEGG_DOMAIN', "\"$fronteggDomain\""
        buildConfigField "String", 'FRONTEGG_CLIENT_ID', "\"$fronteggClientId\""
        buildConfigField "Boolean", 'FRONTEGG_USE_ASSETS_LINKS', "true" /** For using frontegg domain for deeplinks **/
        buildConfigField "Boolean", 'FRONTEGG_USE_CHROME_CUSTOM_TABS', "true"  /** For using custom chrome tab for social-logins **/
    }
}

注意: FRONTEGG_USE_ASSETS_LINKS 默认为 trueFRONTEGG_USE_CHROME_CUSTOM_TABS 默认为 true。 因此,如果您未设置这些值,我们将使用默认值。

如果 android 部分内没有 buildConfig=true,请在 android/app/build.gradle 中添加它:

android {
  buildFeatures {
    buildConfig = true
  }
}

配置Android AssetLinks

配置您的Android AssetLinks 是为了实现魔法链接认证、重置密码、激活账户/使用身份提供商登录。

要将您的 AssetLinks 添加到您的Frontegg应用,您需要更新每个集成的Frontegg环境中您想要使用的 AssetLinks。发送POST请求到 https://api.frontegg.com/vendors/resources/associated-domains/v1/android 并附带以下有效负载:

{
    "packageName": "YOUR_APPLICATION_PACKAGE_NAME",
    "sha256CertFingerprints": ["YOUR_KEYSTORE_CERT_FINGERPRINTS"]
}

每个Android应用有多个证书指纹,要获取您的 DEBUG sha256CertFingerprint,您需要运行以下命令:

对于调试模式,运行以下命令并复制 SHA-256 值:

注意:确保选择的变体和配置等于 debug

./gradlew signingReport

对于发布模式,使用keytool从您的 Release keystore文件中提取SHA256:

keytool -list -v -keystore /PATH/file.jks -alias YourAlias -storepass *** -keypass ***

启用Chrome自定义标签页进行社交登录

要在Android应用中启用使用Chrome自定义标签页进行社交登录,您需要修改 android/app/build.gradle 文件。添加一个布尔类型的 buildConfigField 用于 FRONTEGG_USE_CHROME_CUSTOM_TABS 标志并将其设置为true。

默认情况下,SDK默认使用Chrome浏览器进行社交登录。

def fronteggDomain = "FRONTEGG_DOMAIN_HOST.com" // 不包括协议 https://
def fronteggClientId = "FRONTEGG_CLIENT_ID"

android {
   defaultConfig {

       manifestPlaceholders = [
               "package_name" : applicationId,
               "frontegg_domain" : fronteggDomain,
               "frontegg_client_id": fronteggClientId
       ]

       buildConfigField "String", 'FRONTEGG_DOMAIN', "\"$fronteggDomain\""
       buildConfigField "String", 'FRONTEGG_CLIENT_ID', "\"$fronteggClientId\""
       
       buildConfigField "Boolean", 'FRONTEGG_USE_CHROME_CUSTOM_TABS', "true"
   }
}

多应用Android支持

本指南概述了配置Android应用以支持多个应用的步骤。

步骤1:修改Build.gradle文件

build.gradle 文件中添加 FRONTEGG_APPLICATION_ID 构建配置字段:

def fronteggApplicationId = "your-application-id-uuid"
...
android {
    ...
    buildConfigField "String", 'FRONTEGG_APPLICATION_ID', "\"$fronteggApplicationId\""
}

用法

将根Widget包装在FronteggProvider中

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: FronteggProvider(
        child: const MainPage(),
      ),
    );
  }
}

或者使用 provider 插件或其他合适的插件包装,不要忘记 dispose FronteggFlutter

import 'package:flutter/material.dart';
import 'package:frontegg_flutter/frontegg_flutter.dart';
import 'package:provider/provider.dart';

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Provider(
        create: (_) => FronteggFlutter(),
        dispose: (_, frontegg) => frontegg.dispose(),
        child: const MainPage(),
      ),
    );
  }
}

访问Frontegg实例

要获取 FronteggFlutter 实例,请使用 Frontegg BuildContext扩展:

class MainPage extends StatelessWidget {
  const MainPage({super.key});

  @override
  Widget build(BuildContext context) {
    final frontegg = context.frontegg;
    return const SizedBox();
  }
}

使用frontegg登录

要使用frontegg登录,可以使用 context.frontegg 访问器并调用 login 方法:

class MainPage extends StatelessWidget {
  const MainPage({super.key});

  @override
  Widget build(BuildContext context) {
    final frontegg = context.frontegg;
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          child: const Text("Login"),
          onPressed: () async {
            await frontegg.login();
          },
        ),
      ),
    );
  }
}

切换frontegg租户

要使用frontegg切换租户,可以使用 context.frontegg 访问器并调用 switchTenant 方法:

class MainPage extends StatelessWidget {
  const MainPage({super.key});

  @override
  Widget build(BuildContext context) {
    final frontegg = context.frontegg;
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          child: const Text("Switch Tenant"),
          onPressed: () async {
            final tenantId = "TENANT_ID";
            await frontegg.switchTenant(tenantId);
          },
        ),
      ),
    );
  }
}

Frontegg状态

FronteggPlugin 具有一个 FronteggState,该状态根据插件的流程更改:

class FronteggState {
  final String? accessToken;
  final String? refreshToken;
  final FronteggUser? user;
  final bool isAuthenticated;
  final bool isLoading;
  final bool initializing;
  final bool showLoader;
  final bool appLink;
}

要获取 FronteggFlutter 的状态,有两种选择:

  1. 获取 currentState
@override
Widget build(BuildContext context) {
  final frontegg = context.frontegg;
  final fronteggState = frontegg.currentState;
}
  1. 监听 stateChanged 流:
import 'package:flutter/material.dart';
import 'package:frontegg_flutter/frontegg_flutter.dart';
import 'package:frontegg_flutter_example/login_page.dart';
import 'package:frontegg_flutter_example/user_page.dart';

class MainPage extends StatelessWidget {
  const MainPage({super.key});

  @override
  Widget build(BuildContext context) {
    final frontegg = context.frontegg;
    return Scaffold(
      body: Center(
        child: StreamBuilder<FronteggState>(
          stream: frontegg.stateChanged,
          builder: (BuildContext context, AsyncSnapshot<FronteggState> snapshot) {
            if (snapshot.hasData) {
              final state = snapshot.data!;
              if (state.isAuthenticated && state.user != null) {
                return const UserPage();
              } else if (state.initializing) {
                return const CircularProgressIndicator();
              } else {
                return const LoginPage();
              }
            }

            return const SizedBox();
          },
        ),
      ),
    );
  }
}

其他frontegg功能

frontegg还为您提供以下功能:

  1. logout - 从 FronteggFlutter 注销;
  2. refreshToken - 仅在必要时刷新 accessTokenrefreshToken,如果刷新成功则返回 true
  3. getConstants - 返回 Frontegg Flutter 初始化常量;
  4. directLoginAction - 使用 typedata 直接登录;
  5. registerPasskeys - 注册用户passkey;
  6. loginWithPasskeys - 使用注册的用户passkey登录。
  7. requestAuthorize - 使用刷新令牌和可选设备令牌Cookie请求授权。

已知问题

Android

如果您遇到 MissingPluginException 错误:

The following MissingPluginException was thrown while activating platform stream on channel frontegg_flutter/state_stream:
MissingPluginException(No implementation found for method listen on channel frontegg_flutter/state_stream)

请向 proguard-rules.pro 文件中添加以下行:

-keepclasseswithmembers class com.frontegg.** {*;}

更多关于Flutter前端管理与安全插件frontegg_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter前端管理与安全插件frontegg_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中集成和使用frontegg_flutter插件的示例代码。frontegg_flutter是一个用于前端管理和安全功能的Flutter插件,它可以帮助开发者轻松集成用户管理、身份验证、权限控制等功能。

步骤一:添加依赖

首先,在你的Flutter项目的pubspec.yaml文件中添加frontegg_flutter依赖:

dependencies:
  flutter:
    sdk: flutter
  frontegg_flutter: ^最新版本号 # 请替换为实际的最新版本号

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

步骤二:配置Frontegg

在你的Flutter应用的主文件中(通常是main.dart),你需要配置和初始化frontegg_flutter插件。

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

void main() {
  // 初始化Frontegg
  Frontegg.instance.init(
    apiKey: '你的API_KEY', // 请替换为你的API Key
    tenantId: '你的TENANT_ID', // 请替换为你的Tenant ID
    env: '你的ENV', // 例如 'production' 或 'development'
    config: {
      // 你可以在这里添加其他配置参数
      'someConfigKey': 'someConfigValue',
    },
    onInitSuccess: () {
      // 初始化成功后的回调
      print('Frontegg initialized successfully');
    },
    onInitError: (error) {
      // 初始化失败后的回调
      print('Failed to initialize Frontegg: $error');
    },
  );

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

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

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Demo Home Page'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            // 打开Frontegg管理界面
            Frontegg.instance.openWidget(context);
          },
          child: Text('Open Frontegg'),
        ),
      ),
    );
  }
}

步骤三:处理用户认证和权限

在实际应用中,你可能需要处理用户的认证和权限。frontegg_flutter插件提供了与Frontegg服务交互的API,你可以使用这些API来处理用户的登录、注销和权限检查等操作。

以下是一个简单的示例,展示了如何使用frontegg_flutter插件进行用户登录:

Future<void> loginUser(String email, String password) async {
  try {
    // 调用Frontegg的登录API
    await Frontegg.instance.login(email: email, password: password);
    print('User logged in successfully');
    // 这里可以跳转到应用的主页面或其他逻辑
  } catch (error) {
    print('Failed to log in user: $error');
    // 处理登录失败的情况,例如显示错误消息
  }
}

你可以在按钮点击事件或其他适当的地方调用loginUser函数:

ElevatedButton(
  onPressed: () {
    loginUser('user@example.com', 'password123');
  },
  child: Text('Login'),
),

注意

  • 请确保你已经正确设置了Frontegg服务的API Key、Tenant ID和其他必要的配置。
  • 根据你的应用需求,你可能需要调整Frontegg的配置和API调用。
  • frontegg_flutter插件的API可能会随着版本的更新而变化,请参考官方文档以获取最新的API信息和最佳实践。

以上示例代码展示了如何在Flutter项目中集成和使用frontegg_flutter插件进行前端管理和安全功能。希望这对你有所帮助!

回到顶部