MASA MAUI Plugin (五)Android 指纹识别
背景
MAUI的出现,赋予了广大Net开发者开发多平台应用的能力,MAUI 是Xamarin.Forms演变而来,但是相比Xamarin性能更好,可扩展性更强,结构更简单。但是MAUI对于平台相关的实现并不完整。所以MASA团队开展了一个实验性项目,意在对微软MAUI的补充和扩展,
项目地址https://github.com/BlazorComponent/MASA.Blazor/tree/main/src/Masa.Blazor.Maui.Plugin
每个功能都有单独的demo演示项目,考虑到app安装文件体积(虽然MAUI已经集成裁剪功能,但是该功能对于代码本身有影响),届时每一个功能都会以单独的nuget包的形式提供,方便测试,现在项目才刚刚开始,但是相信很快就会有可以交付的内容啦。
前言
本系列文章面向移动开发小白,从零开始进行平台相关功能开发,演示如何参考平台的官方文档使用MAUI技术来开发相应功能。
介绍
在 API 级别 23 (Android 6.0) 设备上引入指纹扫描仪为应用程序提供了传统的用户名/密码用户身份验证的替代方法。 相较于用户名和密码,采用指纹对用户进行身份验证使应用程序安全性的实现更具隐私性,之后 API-28(Android9.0) 中添加了生物识别身份验证Biometric,增加了人脸认证相关功能。我们今天讨论的只涉及指纹认证,考虑到兼容性问题采用API - 23 (Android 6.0) 版本提供的 FingerprintManager API,经过测试可以在Android 6.0 -11.0中正常工作,如果您需要人脸验证相关功能请参考链接: androidx.biometric,实现细节与本文类似。
思路
我们先看一下Android 的指纹验证方法核心的指纹管理类FingerprintManagerCompat ,fingerprintManager是通过FingerprintManagerCompat.from(Context context)来创建的。
JAVA代码 FingerprintManagerCompat fingerprintManager= FingerprintManagerCompat.from(Context context);
1、检查资格:
1、需要检查设备是否支持指纹。 2、需要检查设备是否受保护 - 用户必须使用屏幕锁保护设备。 如果用户未使用屏幕锁保护设备,但是当前应用程序对于安全性要求很高,则应通知用户必须配置屏幕锁。 3、需要检查用户是否已经注册指纹 - 用户必须至少有一个指纹已注册到操作系统。 此权限检查应在每次尝试进行身份验证之前进行,因为用户有可能随时取消指纹 在MAUI blazor项目的Platforms->Android文件夹添加MasaMauiFingerprintService.cs 类,添加如下两个方法
public static class MasaMauiFingerprintService { private static FingerprintManagerCompat fingerprintManager = FingerprintManagerCompat.From(Android.App.Application.Context); /// <summary> /// Check eligibility /// </summary> /// <returns>error message</returns> public static async Task<string> CheckingEligibility() { // 1、Check if your hardware supports it if (!fingerprintManager.IsHardwareDetected) { return "IsHardwareDetected"; } // 2、Check if the user is using a screen lock // KeyguardManager: Lock screen management class var keyguardManager = Android.App.Application.Context.GetSystemService(Context.KeyguardService) as KeyguardManager; if (!keyguardManager.IsKeyguardSecure) { return "The device does not have a screen lock set"; } // 3、Check if at least one fingerprint is registered if (!fingerprintManager.HasEnrolledFingerprints) { return "The device does not have a fingerprint set, please set at least one fingerprint"; } var granted = await CheckAndRequestFingerprintPermission(); if (!granted) { return "Permissions not granted"; } return string.Empty; } /// <summary> /// Permission check /// </summary> /// <returns></returns> private static async Task<bool> CheckAndRequestFingerprintPermission() { var status = await Permissions.CheckStatusAsync<AndroidFingerprintPermissions>(); if (status == PermissionStatus.Granted) return true; status = await Permissions.RequestAsync<AndroidFingerprintPermissions>(); if (status == PermissionStatus.Granted) return true; return false; } /// <summary> /// Permissions required for fingerprints /// </summary> private class AndroidFingerprintPermissions : Permissions.BasePlatformPermission { public override (string androidPermission, bool isRuntime)[] RequiredPermissions => new List<(string androidPermission, bool isRuntime)> { (global::Android.Manifest.Permission.UseFingerprint, true), }.ToArray(); } }
CheckingEligibility依次检查设备是否支持蓝牙(IsHardwareDetected)、设备是否有屏幕锁(IsKeyguardSecure)这里需要一个KeyguardManager的类帮助检查、是否注册了至少一个指纹(HasEnrolledFingerprints)、是否统一了使用指纹相关权限。
2、扫描指纹实现
现在,我们使用FingerprintManager的Authenticate方法进行指纹验证,
JAVA代码 public void authenticate (FingerprintManager.CryptoObject crypto, CancellationSignal cancel, int flags, FingerprintManager.AuthenticationCallback callback, Handler handler)
参数: crypto FingerprintManager.CryptoObject: 这是一个加密类的对象,指纹扫描器会使用这个对象来判断认证结果的合法性。这个对象可以是null,但是这样的话,就意味这app无条件信任认证结果,所以这个过程可能被攻击,数据可以被篡改。因此,建议这个参数不要置为null。 cancel CancellationSignal:这个对象用来在指纹识别器扫描用户指纹的是时候取消当前的扫描操作,如果不取消的话,那么指纹扫描器会移植扫描直到超时(一般为30s,取决于具体的厂商实现),这样的话就会比较耗电。建议这个参数不要置为null。识别过程中可以手动取消指纹识别 flags int:没用,传 0 callback FingerprintManager.AuthenticationCallback:要接收身份验证事件的回调方法, 此值不能为 null handler Handler:FingerprintManagerCompat将会使用这个handler中的looper来处理来自指纹识别硬件的消息。一般来说,我们开发的时候可以直接传null,因为FingerprintManagerCompat会默认使用app的main looper来处理
我们继续在当前目录下添加CryptoObjectHelper.cs类
public class CryptoObjectHelper { // 键值名称,应用中需要保持唯一 static readonly string KEY_NAME = "com.masa-maui-blazor.android.sample.fingerprint_authentication_key"; // 写死不用改 static readonly string KEYSTORE_NAME = "AndroidKeyStore"; // 加密算法参数 不用改 static readonly string KEY_ALGORITHM = KeyProperties.KeyAlgorithmAes; static readonly string BLOCK_MODE = KeyProperties.BlockModeCbc; static readonly string ENCRYPTION_PADDING = KeyProperties.EncryptionPaddingPkcs7; static readonly string TRANSFORMATION = KEY_ALGORITHM + "/" + BLOCK_MODE + "/" + ENCRYPTION_PADDING; readonly KeyStore _keystore; public CryptoObjectHelper() { _keystore = KeyStore.GetInstance(KEYSTORE_NAME); _keystore.Load(null); } public FingerprintManagerCompat.CryptoObject BuildCryptoObject() { var cipher = CreateCipher(); return new FingerprintManagerCompat.CryptoObject(cipher); } Cipher CreateCipher(bool retry = true) { var key = GetKey(); var cipher = Cipher.GetInstance(TRANSFORMATION); try { cipher.Init(CipherMode.EncryptMode, key); } catch (KeyPermanentlyInvalidatedException e) { _keystore.DeleteEntry(KEY_NAME); if (retry) { CreateCipher(false); } else { throw new Exception("Could not create the cipher for fingerprint authentication.", e); } } return cipher; } IKey GetKey() { IKey secretKey; if (!_keystore.IsKeyEntry(KEY_NAME)) { CreateKey(); } secretKey = _keystore.GetKey(KEY_NAME, null); return secretKey; } void CreateKey() { var keyGen = KeyGenerator.GetInstance(KeyProperties.KeyAlgorithmAes, KEYSTORE_NAME); var keyGenSpec = new KeyGenParameterSpec.Builder(KEY_NAME, KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt) .SetBlockModes(BLOCK_MODE) .SetEncryptionPaddings(ENCRYPTION_PADDING) .SetUserAuthenticationRequired(true) .Build(); keyGen.Init(keyGenSpec); keyGen.GenerateKey(); } }
CryptoObjectHelper 类使用 Android KeyGenerator 生成密钥并安全地将其存储在设备上。 创建的键类型的元数据由类的 KeyGenParameterSpec 实例提供。 使用GetInstance工厂方法实例化 AKeyGenerator。 上述代码使用 (AES) 作为加密算法。 KeyGenParameterSpec.Builde包装具体的AES加密配置信息, SetUserAuthenticationRequired(true) 表示在使用密钥之前需要用户身份验证。
我们在MasaMauiFingerprintService添加一个验证的方法,其中自定义的MasaMauiAuthCallback,在下面一节介绍。
public static void FingerPrintAuthentication() { fingerprintManager.Authenticate(new CryptoObjectHelper().BuildCryptoObject(), 0, new CancellationSignal(), new MasaMauiAuthCallback(), null); }
3、响应身份验证回调
我们在当前目录继续添加CallBack类MasaMauiAuthCallback.cs ,该类需要继承FingerprintManagerCompat.AuthenticationCallback,至少需要重写OnAuthenticationSucceeded方法
public class MasaMauiAuthCallback : FingerprintManagerCompat.AuthenticationCallback { // 随便写,但是app内保持唯一 byte[] SECRET_BYTES = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; public override void OnAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) { if (result.CryptoObject.Cipher != null) //使用了Cipher { var doFinalResult = result.CryptoObject.Cipher.DoFinal(SECRET_BYTES); if (doFinalResult.Any()) { MessagingCenter.Send<MasaMauiAuthCallback,string>(this, "Validation", "验证成功"); } } else { // 没有使用Cipher? // 我们这里的示例使用了Cipher,暂时不考虑不适用的情况 } } public override void OnAuthenticationFailed() { // 通知用户验证失败 MessagingCenter.Send<MasaMauiAuthCallback, string>(this, "Validation", "验证失败"); } }
除了OnAuthenticationSucceeded和OnAuthenticationFailed之外,还有onAuthenticationHelp和onAuthenticationError 我们这里暂不考虑其他两种情景,有兴趣可以参考链接: AuthenticationCallback 这里为了方便演示,验证成功或者失败都是通过MessagingCenter消息发送出去,在使用的时候需要订阅对应topic,来获取验证结果。
4、测试
新建一个MAUI Blazor项目Masa.Blazor.Maui.Plugin.BiometricsSample 在AndroidManifest.xml文件中添加指纹需要的权限 USE_FINGERPRINT
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
简单修改一下Index.razor便于测试 Index.razor:
@page "/" Welcome to your new app. <MButton Block OnClick="Fingerprint">验证指纹</MButton>
Index.razor.cs:
using Masa.Blazor.Maui.Plugin.Biometrics; using Microsoft.AspNetCore.Components; namespace Masa.Blazor.Maui.Plugin.BiometricsSample.Pages { public partial class Index { [Inject] private IPopupService PopupService { get; set; } private async Task Fingerprint() { var checkingEligibilityErrorMessage = await MasaMauiFingerprintService.CheckingEligibility(); if (string.IsNullOrEmpty(checkingEligibilityErrorMessage)) { await HandledValidationAsync(); MasaMauiFingerprintService.FingerPrintAuthentication(); } else { await PopupService.ToastErrorAsync(checkingEligibilityErrorMessage); } } private async Task HandledValidationAsync() { // Cancel your subscription first to prevent duplicate subscriptions MessagingCenter.Unsubscribe<MasaMauiAuthCallback, string>(this, "Validation"); MessagingCenter.Subscribe<MasaMauiAuthCallback, string>(this, "Validation", (sender, arg) => { PopupService.ToastInfoAsync(arg); }); } } }
这里我使用到MAUI提供的发布和订阅消息MessagingCenter, 参考连接链接: MessagingCenter 代码比较简单,先检查资格,没有报错信息之后开启指纹验证,并异步接收callback方法发布的消息。 启动一下,分别用正确和错误的指纹进行测试: 不同的手机指纹验证的UI不同,我这里是vivo的手机
如果你对我们的开源项目感兴趣,无论是代码贡献、使用、提 Issue,欢迎联系我们
- WeChat:MasaStackTechOps
- QQ:7424099

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
GitHub Octoverse 报告:HCL 增长最快,PHP 使用量下降,开源社区运营增加
GitHub 发布了 2022 年度Octoverse 报告,涵盖了对开源软件的探索,包括其对世界和公司的影响;以及影响软件开发的关键趋势内容。报告引用了梅赛德斯-奔驰技术创新的 FOSS 大使 Wolfgang Gehring 的一句话称,“如今,如果不进行开源,你将无法再开发软件。” 当我们10 年前发布第一份 Octoverse 报告以庆祝 GitHub 上用户达 280 万人时,我们无法预测开源会对世界产生的影响。 2012 年,大多数企业只使用开源软件 (OSS) 来运行他们的 Web 服务器——即使Red Hat 实现了 10 亿美元的估值;其他关键的知名项目,如 Kubernetes 和 Docker,还没有发布。 今天,我们生活在一个非常不同的世界。 报告探讨了“开源对世界真正产生了什么样的影响,它是如何改变企业的?” 这一问题,并发现了三个值得关注的大趋势: 开发人员在 2022 年大量使用 Hashicorp 配置语言 (HCL)、Shell 和 Go 编程语言,这表明基础设施即代码 (IaC) 实践越来越多地被 GitHub 上的项目(包括开源项目)采用。HCL ...
- 下一篇
机器学习编译器的前世今生
作者|Chip Huyen 翻译|胡燕君、贾川、程浩源 我承认,在大学的编译器课上哭了,后来我选择成为一名机器学习工程师,以为再也不用被编译器烦扰。 然而,当我逐渐了解ML模型如何投入生产应用,关于编译器的问题不断涌现。在许多用例中,尤其是用边缘设备运行ML模型时,模型的成功与否仍然取决于运行它的硬件(https://hardwarelottery.github.io/)。因此,了解模型的编译和优化,以及模型在不同硬件加速器上的运行非常重要。 理想情况下,我们不需要特别关注编译器,一切都会“正常工作”。然而,要实现这个目标还有很长的路要走。 如今,越来越多公司希望用边缘设备运行ML模型,运行ML模型的硬件越来越多,为了让ML模型能在硬件加速器上更好地运行,也诞生了越来越多编译器——例如MLIR dialects、TVM、XLA、 PyTorch Glow、cuDNN等。根据PyTorch创始人Soumith Chintala的说法,随着ML的应用逐渐成熟,公司之间的竞争将转向谁能更好地编译和优化模型。 ML的下一个战场是编译器(Soumith Chintala,Venture Beat...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Red5直播服务器,属于Java语言的直播服务器
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS8编译安装MySQL8.0.19