在 Xamarin.iOS 中使用触摸 ID 和人脸 ID
iOS 支持两个生物识别身份验证系统:
- 触摸 ID 使用“主页”按钮下的指纹传感器。
- 人脸 ID 使用前置相机传感器通过面部扫描对用户进行身份验证。
iOS 7 引入了触摸 ID,iOS 11 引入了人脸 ID。
这些身份验证系统依赖于一个名为 Secure Enclave 的硬件安全处理器。 Secure Enclave 负责加密人脸和指纹数据的数学表示形式,并使用此信息对用户进行身份验证。 根据 Apple 的说法,人脸和指纹数据不会离开设备,也不会备份到 iCloud。 应用通过本地身份验证 API 与 Secure Enclave 交互,无法检索人脸或指纹数据或直接访问 Secure Enclave。
在提供对受保护内容的访问权限之前,应用可以使用触摸 ID 和人脸 ID 对用户进行身份验证。
本地身份验证上下文
iOS 上的生物识别身份验证依赖于本地身份验证上下文对象,该对象是 LAContext
类的实例。 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 并完成身份验证过程。
示例项目包含模拟数据和视图,用于在身份验证成功时显示数据。