标签:send 原因 google 两种 man mis 管理器 ons sample
Xamarin.Form框架并没有提供指纹认证功能,需要分平台实现!
参考:https://docs.microsoft.com/zh-cn/xamarin/android/platform/fingerprint-authentication/
指纹扫描仪在Android设备上的到来为应用程序提供了用户身份验证的传统用户名/密码方法的替代方案。
使用指纹对用户进行身份验证可以使应用程序合并比用户名和密码更不安全的安全性。
FingerprintManager API使用指纹扫描仪来定位设备,并且运行的API级别为23(Android 6.0)或更高。 这些API在Android.Hardware.Fingerprints命名空间中找到。 Android支持库v4提供了适用于旧版Android的指纹API版本。 兼容性API在Android.Support.v4.Hardware.Fingerprint命名空间中找到,通过Xamarin.Android.Support.v4 NuGet包进行分发。
FingerprintManager(及其支持库对应的FingerprintManagerCompat)是使用指纹扫描硬件的主要类。 此类是围绕系统级服务的Android SDK包装,该服务管理与硬件本身的交互。 它负责启动指纹扫描仪并响应来自扫描仪的反馈。 此类具有一个非常简单的接口,只有三个成员:
以下代码段是如何使用支持库兼容性API调用它的示例:
// context is any Android.Content.Context instance, typically the Activity FingerprintManagerCompat fingerprintManager = FingerprintManagerCompat.From(context); fingerprintManager.Authenticate(FingerprintManager.CryptoObject crypto,int flags,CancellationSignal cancel, FingerprintManagerCompat.AuthenticationCallback callback,Handler handler );
第一个参数是用于通过指纹验证取出AndroidKeyStore中的key的对象,稍后描述。
第二个参数可以用来取消指纹验证,如果想手动关闭验证,可以调用该参数的cancel方法。
第三个参数没什么意义,就是传0就好了。
第四个参数最重要,由于指纹信息是存在系统硬件中的,app是不可以访问指纹信息的,所以每次验证的时候,系统会通过这个callback告诉你是否验证通过、验证失败等。
第五个参数是handler,fingerprint中的消息都通过这个handler来传递消息,如果你传空,则默认创建一个在主线程上的handler来传递消息,没什么用,传null好了。
————————————————
本指南将讨论如何使用FingerprintManager API通过指纹认证来增强Android应用程序。
它将介绍如何实例化和创建CryptoObject来帮助保护指纹扫描仪的结果。 我们将研究应用程序应如何子类化FingerprintManager.AuthenticationCallback并响应指纹扫描仪的反馈。 最后,我们将看到如何在Android设备或仿真器上注册指纹,以及如何使用adb模拟指纹扫描。
CryptoObjec类封装了基于javax.crypto.Cipher的CryptoObject的创建
要求
指纹认证需要Android 6.0(API级别23)或更高版本以及具有指纹扫描器的设备。
必须为要认证的每个用户在设备上注册一个指纹。
这涉及设置使用密码,PIN,滑动模式或面部识别的屏幕锁定。 可以在Android仿真器中模拟某些指纹认证功能。 有关这两个主题的更多信息,请参见“注册指纹”部分。
【即 要调用指纹认证的应用,此手机必须设置了一个锁屏密码 和 录制了至少一个指纹】
首先,让我们先介绍如何配置 Xamarin Android 项目,使应用程序能够使用指纹身份验证:
FingerprintManager
的引用。1、Android 应用程序必须在清单中请求 USE_FINGERPRINT
权限。
2、 获取FingerprintManager的实例
接下来,应用程序必须获取FingerprintManager或FingerprintManagerCompat类的实例。 为了与旧版本的Android兼容,Android应用程序应使用Android支持v4 NuGet包中提供的兼容性API。 以下代码段演示了如何从操作系统中获取适当的对象:
// Using the Android Support Library v4 FingerprintManagerCompat fingerprintManager = FingerprintManagerCompat.From(context); // Using API level 23: FingerprintManager fingerprintManager = context.GetSystemService(Context.FingerprintService) as FingerprintManager;
context是任何Android的 Android.Content.Context。 通常,这是执行身份验证的Activity 。
3、检查资格
应用程序必须执行多项检查,以确保可以使用指纹身份验证。 总共,应用程序使用五个条件来检查资格:
FingerprintManagerCompat fingerprintManager = FingerprintManagerCompat.From(context); if (!fingerprintManager.IsHardwareDetected) { // Code omitted }
KeyguardManager keyguardManager = (KeyguardManager) GetSystemService(KeyguardService); if (!keyguardManager.IsKeyguardSecure) { }
FingerprintManagerCompat fingerprintManager = FingerprintManagerCompat.From(context); if (!fingerprintManager.HasEnrolledFingerprints) { // Can‘t use fingerprint authentication - notify the user that they need to // enroll at least one fingerprint with the device. }
// The context is typically a reference to the current activity. Android.Content.PM.Permission permissionResult = ContextCompat.CheckSelfPermission(context, Manifest.Permission.UseFingerprint); if (permissionResult == Android.Content.PM.Permission.Granted) { // Permission granted - go ahead and start the fingerprint scanner. } else { // No permission. Go and ask for permissions and don‘t start the scanner. See // https://developer.android.com/training/permissions/requesting.html }
每次应用程序提供身份验证选项时,都要检查所有这些条件,以确保用户获得最佳的用户体验。 其设备或操作系统的更改或升级可能会影响指纹身份验证的可用性。 如果您选择缓存任何这些检查的结果,请确保满足升级方案。
有关如何在Android 6.0中请求权限的更多信息,请参阅Android指南“在运行时请求权限”。
指纹身份验证工作流的快速概述:【监听,回调,自己写UI】
FingerprintManager.Authenticate
,同时传递 CryptoObject
和 FingerprintManager.AuthenticationCallback
的实例。 CryptoObject
用于确保指纹身份验证结果未被篡改。FingerprintManager
。 指纹扫描器完成后,它将调用此类的一个回调方法。FingerprintManager.AuthenticationCallback
实例调用方法,将结果返回到应用程序。取消指纹扫描
用户(或应用程序)在启动指纹扫描后可能需要取消指纹扫描。 在这种情况下,请在提供给FingerprintManager的CancellationSignal上调用IsCancelled方法,并在调用它以启动指纹扫描时进行身份验证。
现在我们已经看到了Authenticate方法,让我们更详细地研究一些更重要的参数。
首先,我们将研究响应身份验证回调,它将讨论如何对FingerprintManager.AuthenticationCallback进行子类化,从而使Android应用程序能够对指纹扫描仪提供的结果做出反应。
指纹认证结果的完整性对应用程序很重要-这就是应用程序如何知道用户身份的方式。
从理论上讲,第三方恶意软件可能会拦截和篡改指纹扫描仪返回的结果。 本节将讨论一种保留指纹结果有效性的技术。
FingerprintManager.CryptoObject是Java加密API的包装,FingerprintManager使用它来保护身份验证请求的完整性。
通常,Javax.Crypto.Cipher对象是用于加密指纹扫描器结果的机制。 Cipher对象【意思:密码】本身将使用由应用程序使用Android密钥库API创建的密钥。
为了了解这些类如何协同工作,让我们首先看下面的代码,该代码演示如何创建CryptoObject,然后更详细地进行解释:
public class CryptoObjectHelper { // This can be key name you want. Should be unique for the app. static readonly string KEY_NAME = "com.xamarin.android.sample.fingerprint_authentication_key"; // We always use this keystore on Android. static readonly string KEYSTORE_NAME = "AndroidKeyStore"; // Should be no need to change these values. 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() { Cipher cipher = CreateCipher(); return new FingerprintManagerCompat.CryptoObject(cipher); } Cipher CreateCipher(bool retry = true) { IKey key = GetKey(); Cipher 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() { KeyGenerator keyGen = KeyGenerator.GetInstance(KeyProperties.KeyAlgorithmAes, KEYSTORE_NAME); KeyGenParameterSpec keyGenSpec = new KeyGenParameterSpec.Builder(KEY_NAME, KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt) .SetBlockModes(BLOCK_MODE) .SetEncryptionPaddings(ENCRYPTION_PADDING) .SetUserAuthenticationRequired(true) .Build(); keyGen.Init(keyGenSpec); keyGen.GenerateKey(); } }
程序将使用应用程序创建的key为每个CryptoObject创建一个新的Cipher。key由在CryptoObjectHelper类的开头设置的KEY_NAME变量标识。
请务必意识到,在某些情况下Android可能会使密钥无效:
发生这种情况时,Cipher.Init将抛出KeyPermanentlyInvalidatedException。上面的示例代码将捕获该异常,删除key,然后创建一个新。
下一节将讨论如何创建密钥并将其存储在设备上。
创建密钥key
CryptoObjectHelper类使用Android KeyGenerator来创建密钥并将其存储在设备上。 KeyGenerator类可以创建密钥,但是需要一些有关要创建的密钥类型的元数据。此信息由KeyGenParameterSpec类的实例提供。
使用GetInstance工厂方法实例化KeyGenerator。该示例代码使用 高级加密标准(AES)作为加密算法。 AES会将数据分成固定大小的块,并对每个块进行加密。
接下来,使用KeyGenParameterSpec.Builder创建一个KeyGenParameterSpec。 KeyGenParameterSpec.Builder包装了有关要创建的密钥的以下信息:
一旦创建了KeyGenParameterSpec,它将用于初始化KeyGenerator,它将生成密钥并将其安全地存储在设备上。
【总结:Android.KeyGenerator创建密钥并将其存储在设备上,然后用Javax.Crypto.Cipher 拿创建的密钥 加密指纹扫描器结果,防止扫描结果被篡改】
Using the CryptoObjectHelper
现在,示例代码已将创建CryptoWrapper的大部分逻辑封装到CryptoObjectHelper类中,让我们从本指南的开头重新访问代码,并使用CryptoObjectHelper创建密码并启动指纹扫描器:
protected void FingerPrintAuthenticationExample() { const int flags = 0; /* always zero (0) */ CryptoObjectHelper cryptoHelper = new CryptoObjectHelper(); cancellationSignal = new Android.Support.V4.OS.CancellationSignal(); // Using the Support Library classes for maximum reach FingerprintManagerCompat fingerPrintManager = FingerprintManagerCompat.From(this); // AuthCallbacks is a C# class defined elsewhere in code. FingerprintManagerCompat.AuthenticationCallback authenticationCallback = new MyAuthCallbackSample(this); // Here is where the CryptoObjectHelper builds the CryptoObject. fingerprintManager.Authenticate(cryptohelper.BuildCryptoObject(), flags, cancellationSignal, authenticationCallback, null); }
指纹扫描仪在其自己的后台线程上运行,完成后它将通过在UI线程上调用FingerprintManager.AuthenticationCallback的一种方法来报告扫描结果。 Android应用程序必须提供自己的处理程序,该处理程序扩展此抽象类,并实现以下所有方法:
如果在调用Authenticate时使用了CryptoObject,建议在OnAuthenticationSuccessful中调用Cipher.DoFinal。 如果密码被篡改或初始化不正确,DoFinal将抛出异常,表明指纹扫描仪的结果可能已在应用程序外部被篡改。
具体说明:
1、OnAuthenticationSucceeded检查调用身份验证时是否向密码管理器提供了密码。如果是这样,则在密码上调用DoFinal方法。这将关闭密码,将其还原到其原始状态。如果密码有问题,则DoFinal将引发异常,并且身份验证尝试应被视为失败。
2、OnAuthenticationError和OnAuthenticationHelp回调每个都接收一个整数,指示问题出在哪里。以下部分说明了每种可能的帮助或错误代码。这两个回调起到类似的作用-通知应用程序指纹认证失败。它们的不同之处在于严重性。 OnAuthenticationHelp是用户可恢复的错误,例如快速滑动指纹。 OnAuthenticationError是更严重的错误,例如损坏的指纹扫描仪。
请注意,当通过CancellationSignal.Cancel()消息取消指纹扫描时,将调用OnAuthenticationError。 errMsgId参数的值为5(FingerprintState.ErrorCanceled)。根据要求,AuthenticationCallbacks的实现可能会与其他错误区别对待。
3、成功扫描指纹但与设备注册的任何指纹都不匹配时,将调用OnAuthenticationFailed。
现在,我们已经了解了围绕Android 6.0指纹认证的概念和API,下面我们讨论一些有关使用指纹API的一般建议。
1、Use the Android Support Library v4 Compatibility APIs –通过从代码中删除API检查,从而简化应用程序代码,并使应用程序可以定位到尽可能多的设备。
2、提供指纹认证的替代方法–指纹认证是应用程序认证用户的一种简便快捷的方法,但是,不能认为它会一直有效或可用。指纹扫描仪可能会出现故障,镜头可能变脏,用户可能未将设备配置为使用指纹身份验证,或者此后指纹丢失了。用户也可能不希望在您的应用程序中使用指纹认证。由于这些原因,Android应用程序应提供备用的身份验证过程,例如用户名和密码。
3、使用Google的指纹图标–所有应用程序都应使用Google提供的相同指纹图标。使用标准图标可以使Android用户轻松识别应用中使用指纹身份验证的位置:
Android指纹图标
4、通知用户–应用程序应向用户显示某种形式的通知,表明指纹扫描仪处于活动状态并正在等待触摸或滑动。
参考:Use Touch ID and Face ID with Xamarin.iOS
iOS支持两种生物识别系统:
iOS 7中引入了Touch ID,iOS 11中引入了Face ID。
这些身份验证系统依赖于称为Secure Enclave的基于硬件的安全处理器。 Secure Enclave负责加密面部和指纹数据的数学表示,并使用此信息对用户进行身份验证。 根据Apple的说法,面部和指纹数据不会离开设备,也不会备份到iCloud。
应用程序通过本地身份验证API与Secure Enclave进行交互,并且无法检索人脸或指纹数据或直接访问Secure Enclave。
在提供对受保护内容的访问权限之前,应用程序可以使用Touch ID和Face ID对用户进行身份验证。
iOS上的生物特征认证依赖于本地认证上下文对象,该对象是LAContext类的实例。 LAContext类使您可以:
您可以使用身份验证上下文,通过触摸识别或面部识别等生物识别技术或通过提供设备密码来评估用户的身份。 上下文处理用户交互,并且还连接到Secure Enclave,Secure Enclave是管理生物识别数据的基础硬件元素。 您创建并配置上下文,并要求其执行身份验证。 然后,您将收到一个异步回调,该回调提供身份验证成功或失败的指示,以及一个错误实例,该实例说明失败的原因(如果有)
更多参考:https://developer.apple.com/documentation/localauthentication/lacontext
该示例项目包括一个由AuthenticationViewController支持的AuthenticationView。 此类重写ViewWillAppear方法以检测可用的身份验证方法:
partial class AuthenticationViewController: UIViewController { // ... string BiometryType = ""; public override void ViewWillAppear(bool animated) { base.ViewWillAppear(animated); unAuthenticatedLabel.Text = ""; var context = new LAContext(); var buttonText = ""; // Is login with biometrics possible? if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out var authError1)) { // has Touch ID or Face ID if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0)) { context.LocalizedReason = "Authorize for access to secrets"; // iOS 11 BiometryType = context.BiometryType == LABiometryType.TouchId ? "Touch ID" : "Face ID"; buttonText = $"Login with {BiometryType}"; } // No FaceID before iOS 11 else { buttonText = $"Login with Touch ID"; } } // Is pin login possible? else if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthentication, out var authError2)) { buttonText = $"Login"; // with device PIN BiometryType = "Device PIN"; } // Local authentication not possible else { // Application might choose to implement a custom username/password buttonText = "Use unsecured"; BiometryType = "none"; } AuthenticateButton.SetTitle(buttonText, UIControlState.Normal); } }
当UI将要显示给用户时,将调用ViewWillAppear方法。 此方法定义LAContext的新实例,并使用CanEvaluatePolicy方法确定是否启用了生物特征认证。 如果是这样,它将检查系统版本和BiometryType枚举,以确定哪些生物特征选项可用。
如果未启用生物特征认证,则该应用会尝试回退到PIN认证。 如果生物特征认证和PIN认证均不可用,则设备所有者尚未启用安全功能,并且无法通过本地认证来保护内容。
示例项目中的AuthenticationViewController包含一个AuthenticateMe方法,该方法负责认证用户:
partial class AuthenticationViewController: UIViewController { // ... string BiometryType = ""; partial void AuthenticateMe(UIButton sender) { var context = new LAContext(); NSError AuthError; var localizedReason = new NSString("To access secrets"); // Because LocalAuthentication APIs have been extended over time, // you must check iOS version before setting some properties context.LocalizedFallbackTitle = "Fallback"; if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0)) { context.LocalizedCancelTitle = "Cancel"; } if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0)) { context.LocalizedReason = "Authorize for access to secrets"; BiometryType = context.BiometryType == LABiometryType.TouchId ? "TouchID" : "FaceID"; } // Check if biometric authentication is possible if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out AuthError)) { replyHandler = new LAContextReplyHandler((success, error) => { // This affects UI and must be run on the main thread this.InvokeOnMainThread(() => { if (success) { PerformSegue("AuthenticationSegue", this); } else { unAuthenticatedLabel.Text = $"{BiometryType} Authentication Failed"; } }); }); context.EvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason, replyHandler); } // Fall back to PIN authentication else if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthentication, out AuthError)) { replyHandler = new LAContextReplyHandler((success, error) => { // This affects UI and must be run on the main thread this.InvokeOnMainThread(() => { if (success) { PerformSegue("AuthenticationSegue", this); } else { unAuthenticatedLabel.Text = "Device PIN Authentication Failed"; AuthenticateButton.Hidden = true; } }); }); context.EvaluatePolicy(LAPolicy.DeviceOwnerAuthentication, localizedReason, replyHandler); } // User hasn‘t configured any authentication: show dialog with options else { unAuthenticatedLabel.Text = "No device auth configured"; var okCancelAlertController = UIAlertController.Create("No authentication", "This device does‘t have authentication configured.", UIAlertControllerStyle.Alert); okCancelAlertController.AddAction(UIAlertAction.Create("Use unsecured", UIAlertActionStyle.Default, alert => PerformSegue("AuthenticationSegue", this))); okCancelAlertController.AddAction(UIAlertAction.Create("Cancel", UIAlertActionStyle.Cancel, alert => Console.WriteLine("Cancel was clicked"))); PresentViewController(okCancelAlertController, true, null); } } }
响应于用户点击登录按钮,调用AuthenticateMe方法。 实例化一个新的LAContext对象,并检查设备版本,以确定要在本地身份验证上下文上设置的属性。
调用CanEvaluatePolicy方法以检查是否启用了生物特征认证,并在可能的情况下退回PIN认证,如果没有可用的认证,则最终提供不安全的模式。 如果有身份验证方法可用,则使用EvaluatePolicy方法显示UI并完成身份验证过程。
该示例项目包含模拟数据和一个视图,如果身份验证成功,该视图将显示数据。
标签:send 原因 google 两种 man mis 管理器 ons sample
原文地址:https://www.cnblogs.com/peterYong/p/12434683.html