关于xamarin:MASA-MAUI-Plugin-五Android-指纹识别

背景

MAUI的呈现,赋予了宽广Net开发者开发多平台利用的能力,MAUI 是Xamarin.Forms演变而来,然而相比Xamarin性能更好,可扩展性更强,构造更简略。然而MAUI对于平台相干的实现并不残缺。所以MASA团队发展了一个实验性我的项目,意在对微软MAUI的补充和扩大,

我的项目地址https://github.com/BlazorComp…

每个性能都有独自的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", "验证失败");
        }
    }

除了OnAuthenticationSucceededOnAuthenticationFailed之外,还有onAuthenticationHelponAuthenticationError
咱们这里暂不思考其余两种情景,有趣味能够参考链接: 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

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理