Starbucks Caramel Frappuccino
본문 바로가기
  • 그래 그렇게 조금씩
UIKit/UIKit

Objective-C 생체 인증(Bio Authentication)

by Toughie 2024. 6. 4.

KAKAO-Choonsik

LocalAuthentication

서버를 통한 인증이 아닌, 아이폰이나 아이패드 등에서 비밀번호, 터치아이디, 페이스 아이디로

인증하는 것을 로컬인증이라고 한다. 

내부에 구현되어 있는 LAContext는 사용자 인증을 관리하는데 사용되는 클래스이다. 

LAContext를 통해서 인증 요청 생성, 인증 성공 여부 확인 등의 작업을 처리할 수 있다.

아래의 핵심 메서드 두 개를 살펴보자.

 

canEvaluatePolicy:error:

사용 디바이스가 특정 인증 정책을 평가할 수 있는지 확인하는 메서드이다.

(아이폰을 기준으로 기종마다 비밀번호만 가능, Touch ID 가능, Face ID 가능으로 다름)

 

터치 아이디와 페이스 아이디가 나눠져있을 줄 알았는데, 그냥 Bio 인증으로 묶여 있어서

알아서 자동으로 기종에 따라 정책 평가를 해준다.

(아직 터치아이디와 페이스아이디 둘 다 지원하는 기기가 없어서 가능한 일인듯..)

 

evaluatePolicy:localizedReason:reply:

인증 요청 사유를 유저에게 전달할 수 있고, 실제 인증 과정을 수행한다.

인증 성공/실패에 따라 콜백이 실행된다. 


로컬 인증을 위한 헤더 파일 import, 간단한 확인을 위한 레이블과 버튼 추가

#import "ViewController.h"
#import <LocalAuthentication/LocalAuthentication.h>

@interface ViewController ()
@property (nonatomic, strong) UILabel *statusLabel;
@property (nonatomic, strong) UIButton *authenticateButton;
@end

 

UI세팅 메서드 (viewDidLoad에서 호출)

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UiColor whiteColor];
    [self setupUI];
}

- (void)setupUI {
    self.statusLabel = [[UILabel alloc] initWithFrame:CGRectZero];
    self.statusLabel.text = @"인증 전";
    self.statusLabel.textAlignment = NSTextAlignmentCenter;
    sellf.statusLabel.textColor = [UIColor blackColor];
    [self.view addSubview:self.statusLabel];
    
    self.authenticateButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [self.authenticateButton setTitle:@"Bio Auth" forState:UIControlStateNormal];
    [self.authenticateButton addTarget:self action:@selector(authenticateWithBiometrics) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:self.authenticateButton];
}

 

AutoLayout 설정

-(void) setLayouts {
    self.statusLabel.translateAutoresizingMaskIntoConstraints = NO;
    self.authenticationButton.translatesAUtoresizingMaskIntoConstraints = NO;
    
        [NSLayoutConstraint activateConstraints:@[
        [self.statusLabel.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
        [self.statusLabel.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor constant:-50],
        
        [self.authenticateButton.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
        [self.authenticateButton.topAnchor constraintEqualToAnchor:self.statusLabel.bottomAnchor constant:20]
    ]];
}

 

생체 인증 시도(Face ID / Touch ID)

- (void)authenticateWithBiometricsWithContext:(LAContext *)context reason:(NSString *)reason {
    [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
            localizedReason:reason
                      reply:^(BOOL success, NSError * _Nullable error) {
        dispatch_async(dispatch_get_main_queue(), ^{
            if (success) {
                self.statusLabel.text = @"생체 인증 성공";
            } else {
                self.statusLabel.text = @"생체 인증 실패";
                if (error) {
                    NSLog(@"Biometric authentication error: %@", error.localizedDescription);
                }
            }
        });
    }];
}

 

비밀번호 인증 시도

- (void)authenticateWithPasscodeWithContext:(LAContext *)context reason:(NSString *)reason {
    [context evaluatePolicy:LAPolicyDeviceOwnerAuthentication
            localizedReason:reason
                      reply:^(BOOL success, NSError * _Nullable error) {
        dispatch_async(dispatch_get_main_queue(), ^{
            if (success) {
                self.statusLabel.text = @"비밀번호 인증 완료";
            } else {
                self.statusLabel.text = @"비밀번호 인증 실패";
                if (error) {
                    NSLog(@"Passcode authentication error: %@", error.localizedDescription);
                }
            }
        });
    }];
}

 

생체 인증 시도 후 비밀번호 인증 시도

- (void)authenticateWithBiometrics {
    LAContext *context = [[LAContext alloc] init];
    NSError *error = nil;
    NSString *reason = @"Face ID, Touch ID 또는 비밀번호로 인증";
    
    if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
        [self authenticateWithBiometricsWithContext:context reason:reason];
    } else if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&error]) {
        [self authenticateWithPasscodeWithContext:context reason:reason];
    } else {
        dispatch_async(dispatch_get_main_queue(), ^{
            self.statusLabel.text = @"Face ID, Touch ID 및 비밀번호 사용 불가";
            if (error) {
                NSLog(@"Cannot evaluate policy: %@", error.localizedDescription);
            }
        });
    }
}