FaceID/touchID 接入

翻译自:苹果官方文档
https://developer.apple.com/documentation/localauthentication/logging_a_user_into_your_app_with_face_id_or_touch_id?language=objc

使用Face ID或Touch ID将用户登录到您的应用程序

通过生物身份验证来补充您自己的身份验证方案,使用户可以轻松访问应用程序的敏感部分。

总览

用户喜欢Touch ID和Face ID,因为这些身份验证机制使他们能够以最小的努力安全地访问其设备。当您采用LocalAuthentication框架时,可以简化典型情况下的用户身份验证体验,同时为无法使用生物识别功能的情况提供后备选项。

设置面部识别码用法说明

在任何使用生物识别技术的项目中,请将NSFaceIDUsageDescription键包含在应用程序的Info.plist文件中。没有此密钥,系统将不允许您的应用使用Face ID。该密钥的值是系统在您的应用首次尝试使用Face ID时向用户显示的字符串。该字符串应清楚地说明您的应用为何需要访问此身份验证机制。系统不需要Touch ID的类似用法说明。

创建和配置上下文

您可以使用LAContext实例在应用程序中执行生物特征认证,该实例代理您的应用程序与Secure Enclave之间的交互。首先创建一个上下文:
var context = LAContext()

您可以定制上下文使用的消息传递,以指导用户完成流程。例如,您可以为出现在各种警报视图中的“取消”按钮设置自定义消息:

context.localizedCancelTitle = "Enter Username/Password"

这有助于用户了解,当他们点击按钮时,他们将恢复到您的常规身份验证过程。

测试策略可用性

在尝试进行身份验证之前,请通过调用canEvaluatePolicy(_:error :)方法进行测试,以确保您确实具有身份验证的能力:

if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) {

LAPolicy枚举中选择一个要测试的值。该策略控制身份验证的行为。例如,此样本中使用的deviceOwnerAuthentication策略指示当生物识别失败或不可用时,允许还原为密码。另外,您可以指定deviceOwnerAuthenticationWithBiometrics政策,该政策不允许还原为设备密码。

评估政策

准备好进行身份验证时,请使用已经测试过的相同策略来调用validatePolicy(_:localizedReason:reply :)方法:

context.evaluatePolicy(.deviceOwnerAuthentication,localizedReason:reason){成功,错误

       if success {
        // Move to the main thread because a state update triggers UI changes.
        DispatchQueue.main.async { [unowned self] in
            self.state = .loggedin
        }
    } else {
        print(error?.localizedDescription ?? "Failed to authenticate")
        // Fall back to a asking for username and password.
        // ...
    }
}

对于Touch ID,或者当用户输入密码时,系统会显示验证您在方法调用中提供的原因。重要的是要提供清晰的说明(针对您经营的任何地区),以解释您的应用为何要求用户进行身份验证的原因。您的应用名称已经出现在您提供名称的前面,因此您无需在消息中包含该名称。

(可选)调整您的用户界面以容纳面部ID

除了生物识别扫描操作本身之外,面部ID与触摸ID相比还具有重要的区别。当您的应用尝试使用Touch ID时,系统会显示一条消息,要求用户出示手指进行扫描。用户有时间考虑并可能通过取消提示来中止操作。当您的应用调用人脸ID时,设备会立即开始扫描用户的脸部。用户没有最终的取消机会。为了适应这种行为差异,您可能需要提供不同的UI,具体取决于设备上可用的生物识别技术的种类。

该示例应用程序通过包含带有消息的文本标签来提供不同的UI,该消息警告Face ID用户点击该按钮会立即进行Face ID扫描。该应用程序默认情况下隐藏标签,仅针对当前已注销的具有Face ID的用户显示。具有Touch ID(或完全没有生物特征)的用户不需要此消息,因为他们可以在实际进行扫描之前取消操作。

您可以通过读取上下文的biometryType参数来测试设备支持哪种生物识别:

faceIDLabel.isHidden = (state == .loggedin) || (context.biometryType != .faceID)

在上下文上至少运行一次canEvaluatePolicy(_:error :)方法之后,此参数仅包含有意义的值。

提供生物识别技术的后备替代方案

由于各种原因,身份验证有时会失败或不可用:

用户的设备没有Touch ID或Face ID。
该用户尚未注册生物特征识别,或者未设置密码。
用户取消操作。
触摸ID或面部ID无法识别用户。
您之前已通过调用invalidate()方法使上下文无效。

有关可能的错误情况的完整列表,请参见LAError.Code

此示例应用未实现替代身份验证。在真实应用中,如果遇到本地身份验证错误,请退回自己的身份验证方案,例如询问用户名和密码。使用生物识别技术来补充您已经在做的事情。请勿将生物识别技术作为唯一的身份验证选项。

Swift版本:
import UIKit
import LocalAuthentication

class ViewController: UIViewController {

    @IBOutlet weak var loginButton: UIButton!
    @IBOutlet weak var stateView: UIView!
    @IBOutlet weak var faceIDLabel: UILabel!

    /// An authentication context stored at class scope so it's available for use during UI updates.
    var context = LAContext()

    /// The available states of being logged in or not.
    enum AuthenticationState {
        case loggedin, loggedout
    }

    /// The current authentication state.
    var state = AuthenticationState.loggedout {

        // Update the UI on a change.
        didSet {
            loginButton.isHighlighted = state == .loggedin  // The button text changes on highlight.
            stateView.backgroundColor = state == .loggedin ? .green : .red

            // FaceID runs right away on evaluation, so you might want to warn the user.
            //  In this app, show a special Face ID prompt if the user is logged out, but
            //  only if the device supports that kind of authentication.
            faceIDLabel.isHidden = (state == .loggedin) || (context.biometryType != .faceID)
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // The biometryType, which affects this app's UI when state changes, is only meaningful
        //  after running canEvaluatePolicy. But make sure not to run this test from inside a
        //  policy evaluation callback (for example, don't put next line in the state's didSet
        //  method, which is triggered as a result of the state change made in the callback),
        //  because that might result in deadlock.
        context.canEvaluatePolicy(.deviceOwnerAuthentication, error: nil)

        // Set the initial app state. This impacts the initial state of the UI as well.
        state = .loggedout
    }

    /// Logs out or attempts to log in when the user taps the button.
    @IBAction func tapButton(_ sender: UIButton) {

        if state == .loggedin {

            // Log out immediately.
            state = .loggedout

        } else {

            // Get a fresh context for each login. If you use the same context on multiple attempts
            //  (by commenting out the next line), then a previously successful authentication
            //  causes the next policy evaluation to succeed without testing biometry again.
            //  That's usually not what you want.
            context = LAContext()

            context.localizedCancelTitle = "Enter Username/Password"

            // First check if we have the needed hardware support.
            var error: NSError?
            if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) {

                let reason = "Log in to your account"
                context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason ) { success, error in

                    if success {

                        // Move to the main thread because a state update triggers UI changes.
                        DispatchQueue.main.async { [unowned self] in
                            self.state = .loggedin
                        }

                    } else {
                        print(error?.localizedDescription ?? "Failed to authenticate")

                        // Fall back to a asking for username and password.
                        // ...
                    }
                }
            } else {
                print(error?.localizedDescription ?? "Can't evaluate policy")

                // Fall back to a asking for username and password.
                // ...
            }
        }
    }
}

OC版本:

#import "ViewController.h"
#import 


@interface ViewController () {
    BOOL _isAuthrized;
}


@property(nonatomic, strong) LAContext *context;

@property(nonatomic, strong) UIButton *loginButton;
@property(nonatomic, strong) UIView *stateView;
@property(nonatomic, strong) UILabel *faceIdL;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    [self setUI];
    _isAuthrized = NO;
    
    NSError *error = nil;
    BOOL ss = [self.context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&error];

}


- (UIView *)stateView {
    if (nil == _stateView) {
        _stateView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
        _stateView.backgroundColor = UIColor.greenColor;
    }
    return _stateView;
}

- (UIButton *)loginButton {
    if (nil == _loginButton) {
        _loginButton = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
        [_loginButton setTitle:@"log in" forState:UIControlStateNormal];
        [_loginButton addTarget:self action:@selector(tapBtn) forControlEvents:UIControlEventTouchUpInside];
    }
    return _loginButton;
}

- (void)setUI {
    [self.view addSubview:self.stateView];
    [self.view addSubview:self.loginButton];
}

#pragma mark -
- (void)tapBtn {
    
    if (_isAuthrized == YES) {
        _isAuthrized = NO;
        [self changeUI];
    } else {
        self.context = LAContext.new;
        self.context.localizedCancelTitle = @"Enter Username/Password";
        
        NSError *error = nil;
        
        if ([self.context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&error]) {
            [self.context evaluatePolicy:LAPolicyDeviceOwnerAuthentication localizedReason:@"log in to your account" reply:^(BOOL success, NSError * _Nullable error) {
                if (success) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        self->_isAuthrized = YES;
                    });
                    NSLog(@"%@",@"验证成功");
                    [self changeUI];
                } else {
                    NSLog(@"%@",@"验证失败");
                    self->_isAuthrized = NO;
                    [self changeUI];
                }
            }];
        } else {
            NSLog(@"%@",@"执行失败");
            self->_isAuthrized = NO;
        }
    }
    [self changeUI];
}

- (void)changeUI {
    
    NSLog(@"%d",_isAuthrized);
    dispatch_async(dispatch_get_main_queue(), ^{
        
        [self.loginButton setTitle:self->_isAuthrized ? @"log out" : @"log in" forState:UIControlStateNormal];
        self.stateView.backgroundColor = self->_isAuthrized ? UIColor.greenColor : UIColor.redColor;
    });
    
}
@end

你可能感兴趣的:(FaceID/touchID 接入)