Flutter设备信任验证插件flutter_trusted_device_v2的使用
Flutter设备信任验证插件flutter_trusted_device_v2的使用
这是Fazpass Trusted Device V2的官方Flutter包。
如果您想使用Android原生SDK,可以在这里找到:https://github.com/fazpass-sdk/android-trusted-device-v2
对于iOS版本,您可以在这里找到:https://github.com/fazpass-sdk/ios-trusted-device-v2
您还可以在flutter pub.dev上找到这个包:https://pub.dev/packages/flutter_trusted_device_v2
访问Fazpass官方网站以获取更多产品信息,并查看在线文档以获得更多的技术细节。
最低操作系统要求
- Android 24及以上版本
- iOS 13.0及以上版本
安装
在您的项目根目录下运行以下命令:
$ flutter pub add flutter_trusted_device_v2
这将在您的pubspec.yaml
文件中添加如下一行(并隐式运行flutter pub get
):
dependencies:
flutter_trusted_device_v2: ^<version>
或者,您可以使用编辑器支持的flutter pub get
。请查阅您的编辑器文档了解更多信息。
现在可以在Dart代码中使用:
import 'package:flutter_trusted_device_v2/flutter_trusted_device_v2.dart';
开始使用
在使用此包之前,请务必联系我们以获取公钥和FCM应用ID(仅限iOS)。
该包的主要目的是生成元数据,您可以使用这些元数据与Fazpass REST API通信。但在调用生成元数据方法之前,您需要先通过调用以下方法进行初始化:
Fazpass.instance.init(
androidAssetName: 'AndroidAssetName.pub',
iosAssetName: 'iosAssetName',
iosFcmAppId: 'iosFcmAppId'
);
在Android上开始使用
设置您的公钥
- 打开您的Android文件夹,然后进入
app/src/main/assets/
(如果assets文件夹不存在,请创建一个新的)。 - 将公钥放入此文件夹。
然后,打开您的android MainActivity
文件(app/src/main/kotlin/<app_package>/MainActivity.kt
),并进行一些更改:
// 更改此导入:
// import io.flutter.embedding.android.FlutterActivity
// 更改为:
import io.flutter.embedding.android.FlutterFragmentActivity
// 将MainActivity的父类从FlutterActivity更改为FlutterFragmentActivity
class MainActivity: /*FlutterActivity()*/ FlutterFragmentActivity() {
// ...
}
之后,打开styles.xml
文件(app/src/main/res/values/styles.xml
),并将主题更改为AppCompat主题(或其子类):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 当系统暗模式设置关闭时应用于Android窗口的主题 -->
<!-- 将parent LaunchTheme更改为: -->
<!-- <style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar"> -->
<!-- 更改为: -->
<style name="LaunchTheme" parent="@style/Theme.AppCompat.Light.NoActionBar">
<!-- 显示一个启动屏活动。当Flutter引擎绘制第一帧时自动移除 -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- 应用于Android窗口的主题,一旦进程启动即生效。
此主题确定您的Flutter UI初始化期间以及运行时背后的Android窗口颜色。
此主题仅从Flutter的Android嵌入V2开始使用。 -->
<!-- 将parent NormalTheme更改为: -->
<!-- <style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar"> -->
<!-- 更改为: -->
<style name="NormalTheme" parent="@style/Theme.AppCompat.Light.NoActionBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
如果有夜间样式变体(app/src/main/res/values-night/styles.xml
),则需要将其更改为暗色AppCompat主题:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 当系统暗模式设置开启时应用于Android窗口的主题 -->
<style name="LaunchTheme" parent="@style/Theme.AppCompat.DayNight.NoActionBar">
<!-- 显示一个启动屏活动。当Flutter引擎绘制第一帧时自动移除 -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- 应用于Android窗口的主题,一旦进程启动即生效。
此主题确定您的Flutter UI初始化期间以及运行时背后的Android窗口颜色。
此主题仅从Flutter的Android嵌入V2开始使用。 -->
<style name="NormalTheme" parent="@style/Theme.AppCompat.DayNight.NoActionBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
检索您的应用程序签名
当在Fazpass仪表板中创建新的商户应用时,有一个“签名”输入框。
以下是获取签名的方法:
在主widget的initState()
方法中添加以下代码行:
[@override](/user/override)
void initState() {
super.initState();
// 添加这一行
Fazpass.instance.getAppSignatures().then((value) => print("APPSGN: $value"));
}
然后构建发布版apk。将设备连接到PC并在调试时启动它。打开日志并查询APPSGN
。它的值是一个数组,看起来像这样:[Gw+6AWbS7l7JQ7Umb1zcs1aNA8M=]
。如果有多个项,请选择其中一个。复制签名Gw+6AWbS7l7JQ7Umb1zcs1aNA8M=
并将其填入您的商户应用的签名字段中。
上传您的apk或abb到Play商店后,从Play商店下载您的应用并再次检查应用的签名。如果不同,请确保更新您的商户应用的签名值。
在iOS上开始使用
设置您的公钥
- 在XCode项目中,打开Assets。
- 添加新的数据集作为资产。
- 引用您的公钥到这个资产。
- 命名您的资产。
然后,您需要在Info.plist
文件中声明NSFaceIDUsageDescription
,以便能够生成元数据,因为生成元数据需要用户进行生物识别认证。
然后,在您的XCode项目中的AppDelegate.swift
文件中,覆盖didReceiveRemoteNotification
函数。
override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
// 添加这一行
Fazpass.shared.getCrossDeviceDataFromNotification(userInfo: userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
使用
调用generateMeta()
方法以启动本地身份验证(生物识别/密码)并生成元数据。如果本地身份验证成功,则生成元数据;否则抛出BiometricAuthFailedError
。
String meta = '';
try {
meta = await Fazpass.instance.generateMeta();
} on FazpassException catch (e) {
switch (e) {
case BiometricNoneEnrolledError():
// TODO
break;
case BiometricAuthFailedError():
// TODO
break;
case BiometricUnavailableError():
// TODO
break;
case BiometricUnsupportedError():
// TODO
break;
case EncryptionException():
// TODO
break;
case PublicKeyNotExistException():
// TODO
break;
case UninitializedException():
// TODO
break;
case BiometricSecurityUpdateRequiredError():
// TODO
break;
}
}
异常和错误
UninitializedException
当未调用fazpass
的初始化方法时产生。
PublicKeyNotExistException
- Android: 当在初始化方法中注册的公钥名称在assets目录中不存在时产生。
- iOS: 当在初始化方法中注册的公钥名称作为asset不存在时产生。
EncryptionException
当由于使用了错误的公钥而导致加密失败时产生。
BiometricAuthError
当生物识别身份验证完成时出现错误时产生。(例如:用户取消了生物识别身份验证,用户多次未能通过生物识别身份验证等)
BiometricUnavailableError
- Android: 当设备无法启动生物识别身份验证,因为缺少合适的硬件(例如:无生物识别传感器或无锁屏)或硬件不可用时产生。
- iOS: 当设备无法启动生物识别身份验证,因为生物识别不可用时产生。
BiometricNoneEnrolledError
- Android: 当设备无法启动生物识别身份验证,因为没有生物识别信息(例如:指纹、面部、虹膜)或设备凭据(例如:PIN、密码、图案)注册时产生。
- iOS: 当设备无法启动生物识别身份验证,因为没有生物识别(触控ID或面容ID)或设备密码注册时产生。
BiometricUnsupportedError
- Android: 当设备无法启动生物识别身份验证,因为指定的选项与当前Android版本不兼容时产生。
- iOS: 当设备无法启动生物识别身份验证,因为显示所需的认证用户界面被禁止时产生。要解决此问题,您需要通过将
interactionNotAllowed
属性设置为false
来允许显示认证UI。
Android独有异常
BiometricSecurityUpdateRequiredError
当设备无法启动生物识别身份验证,因为一个或多个硬件传感器发现了一个安全漏洞。受影响的传感器在解决此问题之前不可用时产生。
设置数据收集偏好
此包支持具有多个帐户的应用程序,每个帐户可以有不同的生成元数据设置。要设置数据收集偏好,请调用setSettings()
方法。
// 帐户索引
int accountIndex = 0;
// 创建偏好
FazpassSettings settings = FazpassSettingsBuilder()
.enableSelectedSensitiveData([SensitiveData.location])
.setBiometricLevelToHigh()
.build();
// 保存偏好
await Fazpass.instance.setSettings(accountIndex, settings);
// 使用相同的帐户索引应用已保存的偏好
String meta = await Fazpass.instance.generateMeta(accountIndex: accountIndex);
// 删除已保存的偏好
await Fazpass.instance.setSettings(accountIndex, null);
generateMeta()
方法的accountIndex
参数默认值为-1
。
强烈建议不要将偏好保存到默认帐户索引。如果您的应用程序只允许一个活动帐户,请使用
0
。
数据收集
生成的元数据中收集和存储的数据。根据数据收集方式的不同,数据类型分为三类:一般数据、敏感数据和其他数据。
一般数据总是会被收集,而敏感数据需要更复杂的程序才能被收集。其他数据是一种特殊的情况,它们收集复杂的测试结果,可能会影响generateMeta()
方法的工作方式。
要启用敏感数据收集,您需要设置偏好并指定您想要收集哪些敏感数据。
FazpassSettingsBuilder builder = FazpassSettingsBuilder()
.enableSelectedSensitiveData([
SensitiveData.location,
SensitiveData.simNumbersAndOperators,
SensitiveData.vpn
]);
然后,您需要遵循如何启用每种敏感数据的程序,如其各自的段落中所述。
对于其他数据,您也需要设置偏好并指定您想要启用哪些数据。
FazpassSettingsBuilder builder = FazpassSettingsBuilder()
.setBiometricLevelToHigh();
有关详细信息,请阅读它们各自段落中的描述。
收集的一般数据
- 您的设备平台名称(Android上的值为"android",iOS上的值为"ios")。
- 您的应用程序包名(iOS上的捆绑标识符)。
- 您的应用程序调试状态。
- 您的设备root状态(iOS上的越狱状态)。
- 您的设备模拟器/仿真器状态。
- 您的应用程序克隆状态(仅限Android)。
- 您的设备镜像或投影状态。
- 您的应用程序签名(仅限Android)。
- 您的设备信息(Android/iOS版本、手机品牌/型号、手机类型、手机CPU)。
- 您的网络IP地址。
- 您的网络VPN状态(仅限Android)。
收集的敏感数据
您的设备位置和模拟位置状态
可用性:Android、iOS
要在Android上启用位置,请确保请求用户授予以下权限:
android.permission.ACCESS_COARSE_LOCATION
或android.permission.ACCESS_FINE_LOCATION
android.permission.FOREGROUND_SERVICE
要在iOS上启用位置,请在您的Info.plist
文件中声明NSLocationWhenInUseUsageDescription
。
您的设备SIM号码和运营商(如有)
可用性:Android
要在Android上启用SIM号码和运营商,请确保请求用户授予以下权限:
android.permission.READ_PHONE_NUMBERS
android.permission.READ_PHONE_STATE
您的网络VPN状态
可用性:iOS
要在iOS上启用VPN,请在您的Xcode项目中启用Network Extensions功能。
收集的其他数据
高级生物识别
启用高级生物识别会使generateMeta()
方法仅使用生物识别,防止用户使用密码作为另一种选择。启用此功能后,立即调用generateNewSecretKey()
方法以创建一个将安全地存储在设备密钥库提供程序中的秘密密钥。从此以后,使用高级生物识别偏好调用generateMeta()
会使用新创建的秘密密钥进行加密和解密测试。每次测试失败时,意味着秘密密钥已被无效化,因为发生了以下情况之一:
- 设备注册了新的生物识别信息(新的指纹、面部或虹膜)
- 设备清除了所有生物识别信息
- 设备删除了他们的设备密码(密码、PIN、图案等)
当秘密密钥被无效化时,尝试调用Fazpass Check API将会失败。推荐的操作是在启用高级生物识别的每个帐户上注销,并重新使用低级生物识别设置登录。如果您想在秘密密钥被无效化后重新启用高级生物识别,请确保再次调用generateNewSecretKey()
。
处理传入的跨设备通知
当应用程序处于后台状态(未运行)时,传入的跨设备通知将进入您的系统通知栏并显示为通知。按下所述通知将启动应用程序,并将跨设备数据作为参数传递。当应用程序处于前台状态(当前正在运行)时,传入的跨设备通知将立即发送到应用程序,而不会显示任何通知。
要检索后台状态下的跨设备通知数据,请调用getCrossDeviceDataFromNotification()
方法。
CrossDeviceData data = await Fazpass.instance.getCrossDeviceDataFromNotification();
要检索前台状态下的跨设备通知数据,请调用getCrossDeviceDataStreamInstance()
方法以获取流实例,然后开始监听流。
// 获取流实例
Stream<CrossDeviceData> crossDeviceStream = Fazpass.instance.getCrossDeviceDataStreamInstance();
// 开始监听流
StreamSubscription<CrossDeviceData> crossDeviceSubs = crossDeviceStream.listen((CrossDeviceData data) {
// 每次有传入的跨设备通知时都会被调用
print(data);
if (data.status == "request") {
String notificationId = data.notificationId!;
print(notificationId);
} else if (data.status == "validate") {
String action = data.action!;
print(action);
}
});
// 停止监听流
crossDeviceSubs.cancel();
示例代码
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_trusted_device_v2/flutter_trusted_device_v2.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
[@override](/user/override)
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _meta = 'Not generated yet';
final _fazpass = Fazpass.instance;
[@override](/user/override)
void initState() {
super.initState();
_fazpass.getAppSignatures().then((value) => print("APPSGN: $value"));
initializeFazpass()
.then((value) => setFazpassSettings())
.then((value) => generateMeta());
}
Future<void> initializeFazpass() async {
// 初始化fazpass包
await _fazpass.init(androidAssetName: 'my_public_key.pub');
}
Future<void> setFazpassSettings() async {
// 创建设置
final settings = FazpassSettingsBuilder()
.enableSelectedSensitiveData([SensitiveData.simNumbersAndOperators, SensitiveData.location])
.setBiometricLevelToHigh()
.build();
// 生成新的密钥,以便我们可以使用高级生物识别
await _fazpass.generateNewSecretKey();
// 保存设置
await _fazpass.setSettings(1, settings);
}
Future<void> generateMeta() async {
String meta = 'Failed to generate meta.';
try {
// 使用保存的设置为帐户索引1生成元数据
meta = await _fazpass.generateMeta(accountIndex: 1);
} on FazpassException catch (e) {
switch (e) {
case BiometricNoneEnrolledError():
// TODO
break;
case BiometricAuthFailedError():
// TODO
break;
case BiometricUnavailableError():
// TODO
break;
case BiometricUnsupportedError():
// TODO
break;
case EncryptionException():
// TODO
break;
case PublicKeyNotExistException():
// TODO
break;
case UninitializedException():
// TODO
break;
case BiometricSecurityUpdateRequiredError():
// TODO
break;
}
}
if (!mounted) return;
setState(() {
_meta = meta;
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Text(_meta),
),
),
);
}
}
更多关于Flutter设备信任验证插件flutter_trusted_device_v2的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter设备信任验证插件flutter_trusted_device_v2的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何使用Flutter设备信任验证插件flutter_trusted_device_v2
的示例代码案例。这个插件通常用于验证设备是否可信,例如通过设备指纹、硬件标识符等方式来确认设备的唯一性和安全性。
首先,你需要在pubspec.yaml
文件中添加对该插件的依赖:
dependencies:
flutter:
sdk: flutter
flutter_trusted_device_v2: ^最新版本号 # 请替换为实际可用的最新版本号
然后运行flutter pub get
来安装插件。
接下来,你可以在Flutter项目中编写代码来使用这个插件。以下是一个简单的示例,展示了如何进行设备信任验证:
import 'package:flutter/material.dart';
import 'package:flutter_trusted_device_v2/flutter_trusted_device_v2.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter Device Trust Verification'),
),
body: Center(
child: DeviceTrustVerificationExample(),
),
),
);
}
}
class DeviceTrustVerificationExample extends StatefulWidget {
@override
_DeviceTrustVerificationExampleState createState() => _DeviceTrustVerificationExampleState();
}
class _DeviceTrustVerificationExampleState extends State<DeviceTrustVerificationExample> {
String deviceTrustStatus = 'Checking...';
@override
void initState() {
super.initState();
_checkDeviceTrust();
}
Future<void> _checkDeviceTrust() async {
try {
// 获取设备信任状态
bool isTrusted = await FlutterTrustedDeviceV2.isTrusted();
// 更新UI状态
setState(() {
deviceTrustStatus = isTrusted ? 'Device is Trusted' : 'Device is NOT Trusted';
});
} catch (e) {
// 处理异常
setState(() {
deviceTrustStatus = 'Error: ${e.message}';
});
}
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
deviceTrustStatus,
style: TextStyle(fontSize: 20),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// 这里可以添加重新验证设备信任状态的逻辑,如果需要的话
_checkDeviceTrust();
},
child: Text('Re-check Device Trust'),
),
],
);
}
}
在这个示例中,我们做了以下几件事情:
- 在
pubspec.yaml
文件中添加了flutter_trusted_device_v2
插件的依赖。 - 创建了一个简单的Flutter应用,包含一个按钮和一个显示设备信任状态的文本。
- 在
_DeviceTrustVerificationExampleState
类的initState
方法中,调用FlutterTrustedDeviceV2.isTrusted()
方法来检查设备是否可信,并更新UI状态。 - 在UI中显示设备信任状态,并提供一个按钮来重新检查设备信任状态(如果需要的话)。
请注意,flutter_trusted_device_v2
插件的具体实现和API可能会有所不同,因此你需要参考插件的官方文档和示例代码来确保正确使用该插件。此外,设备信任验证通常涉及敏感信息和安全策略,因此在实际应用中需要谨慎处理。