iOS指紋識(shí)別登錄流程及實(shí)現(xiàn)

指紋.png

閑談

最近一直在追青云志,總覺(jué)得電視劇沒(méi)有小說(shuō)來(lái)的精彩。是的哨毁,大咖們演技堪稱驚艷,劇情改編也很緊湊源武,但不得不說(shuō)很多東西單靠演是達(dá)不到的扼褪,主人公每一刻的內(nèi)心也只能在小說(shuō)中才能看的貼切(為了裝X,哥不惜二百兩買(mǎi)了一沓正版典藏版)粱栖。

看過(guò)的童鞋知道话浇,張小凡手中的法寶,是由攝魂與嗜血珠以張小凡精血為媒淬煉而成闹究。而且此法寶幔崖,有一特大優(yōu)秀品質(zhì),那就是除了與張小凡有血緣關(guān)系的人之外渣淤,即便你有通天本領(lǐng)也不能操控赏寇,忠誠(chéng)如此夫復(fù)何求啊,說(shuō)到這里大概就扯到正題了价认,對(duì)的嗅定,此法寶自帶安全驗(yàn)證功能,類似我們今天的密碼校驗(yàn)與指紋識(shí)別驗(yàn)證功能用踩。

指紋識(shí)別簡(jiǎn)析

蘋(píng)果設(shè)計(jì)的iOS是以安全性為核心的渠退,不管是沙盒機(jī)制忙迁,還是代碼簽名等,他們的最終目的都是為了安全智什。

iOS 安全架構(gòu)圖

自iPhone 5S始,蘋(píng)果公司推出了全新生物安全識(shí)別技術(shù)---指紋識(shí)別驗(yàn)證(Touch ID)丁屎。使得我們可以更快荠锭、更輕松地對(duì)設(shè)備進(jìn)行安全的訪問(wèn)〕看ǎ可貴的是证九,Touch ID做到了從任意角度讀取指紋數(shù)據(jù),克服了基于密碼進(jìn)行鎖定的不便共虑。除此之外愧怜,蘋(píng)果還加入必須進(jìn)行密碼校驗(yàn)的場(chǎng)景,進(jìn)一步確保安全妈拌,例如【1】:

  • 剛開(kāi)機(jī)或重啟拥坛;
  • 超過(guò) 48 小時(shí)未解鎖設(shè)備;
  • 設(shè)備收到了遠(yuǎn)程鎖定命令尘分;
  • 五次未能成功匹配指紋猜惋;
  • 進(jìn)入Touch ID設(shè)置模塊或更新新指紋;

最重要的一點(diǎn)培愁,蘋(píng)果公司提供Touch ID給第三方應(yīng)用程序使用著摔,程序只會(huì)收到認(rèn)證是否成功的通知,而無(wú)法訪問(wèn) Touch ID 或與已注冊(cè)指紋相關(guān)的數(shù)據(jù)定续,這一點(diǎn)對(duì)安全而言尤為重要谍咆。

為了獲得更高的安全性,很多銀行類私股、支付類APP都集成了指紋摹察、手勢(shì)等二次驗(yàn)證功能。今天我們就重點(diǎn)來(lái)談?wù)凾ouch ID集成到APP的具體流程及實(shí)現(xiàn)倡鲸。

流程分析

指紋登錄流程:

首次登錄.png

二次啟動(dòng)后識(shí)別登錄:
指紋驗(yàn)證登錄.png

使用過(guò)指紋登錄的朋友港粱,大概都知道上面的流程。
這個(gè)業(yè)務(wù)實(shí)現(xiàn)的難點(diǎn)在于旦签,首次登錄成功并啟用指紋授權(quán)--->退出APP后--->二次啟動(dòng)APP查坪,如何判斷是否要啟用指紋登錄驗(yàn)證呢?這時(shí)就需要我們對(duì)數(shù)據(jù)持久化和數(shù)據(jù)共享有較深的理解宁炫,很多APP開(kāi)發(fā)者偿曙,在開(kāi)發(fā)登錄保持的時(shí)候,大都會(huì)使用持久化數(shù)據(jù)的方式羔巢,存儲(chǔ)成功登錄的標(biāo)記望忆。但對(duì)于安全性較高的APP罩阵,每次重新啟動(dòng)時(shí)都會(huì)校驗(yàn)登錄狀態(tài),單靠持久化數(shù)據(jù)是不夠的启摄。

我的解決方案是:
通過(guò)三個(gè)數(shù)據(jù)進(jìn)行登錄保持稿壁,

  • loginState:持久化數(shù)據(jù),用于存儲(chǔ)用戶登錄成功歉备,未激活狀態(tài)傅是;
  • startAutoLoginState:持久化數(shù)據(jù),是否開(kāi)啟指紋識(shí)別授權(quán)蕾羊;
  • isAppCurrentLoginState:共享數(shù)據(jù)喧笔,登錄激活狀態(tài),該狀態(tài)的特點(diǎn)龟再,每次重新啟動(dòng)APP都會(huì)重新初始化數(shù)據(jù)书闸。
首次登錄:

三個(gè)數(shù)據(jù)變化情況,

狀態(tài) loginState startAutoLoginState isAppCurrentLoginState
登錄之前 nil或NO nil或NO NO
登錄成功 YES nil或NO YES
啟用指紋授權(quán) YES YES YES
不啟用授權(quán) YES NO YES
二次驗(yàn)證登錄(指紋登錄):

三個(gè)數(shù)據(jù)變化情況利凑,

  • 如果loginState和startAutoLoginState同為YES浆劲,即可進(jìn)行指紋登錄驗(yàn)證,以下為數(shù)據(jù)變化情況哀澈;
狀態(tài) loginState startAutoLoginState isAppCurrentLoginState
驗(yàn)證之前 YES YES NO
驗(yàn)證失敗 NO YES NO
驗(yàn)證成功 YES YES YES
  • 否則梳侨,重新登錄。

核心代碼實(shí)現(xiàn)

判斷設(shè)備是否支持指紋識(shí)別

/**
 * 判斷設(shè)備是否支持指紋識(shí)別
 */
- (IBAction)loginBtnAction:(UIButton *)sender
{

    [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:YES] forKey:@"loginState"];

    EVNHelper *helper = [EVNHelper shareHelper];
    helper.isAppCurrentLoginState = YES;

    LAContext *context = [[LAContext alloc] init]; // 初始化上下文對(duì)象
    NSError *error = nil;
    // 判斷設(shè)備是否支持指紋識(shí)別功能
    if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error])
    {
        // 支持指紋驗(yàn)證
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"登錄成功日丹!" message:@"是否啟用指紋登錄" preferredStyle:UIAlertControllerStyleAlert];

        __weak typeof (self) weakSelf = self;

        UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"稍后" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {

            [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:NO] forKey:@"startAutoLoginState"];
            weakSelf.transLoginStateBlock(); // 回傳
            [self dismissViewControllerAnimated:YES completion:nil];
        }];

        UIAlertAction *startUseAction = [UIAlertAction actionWithTitle:@"啟用" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {

            [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:YES] forKey:@"startAutoLoginState"];
            weakSelf.transLoginStateBlock(); // 回傳
            [self dismissViewControllerAnimated:YES completion:nil];

        }];
        [alertController addAction:cancelAction];
        [alertController addAction:startUseAction];
        
        [self presentViewController:alertController animated:YES completion:nil];
    }
    else
    {
        [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:NO] forKey:@"startAutoLoginState"];
        self.transLoginStateBlock(); // 回傳
        [self dismissViewControllerAnimated:YES completion:nil];
    }

}

指紋登錄驗(yàn)證

/**
 * 指紋登錄驗(yàn)證
 */
- (void)loadAuthentication
{
    __weak typeof(self) weakSelf = self;

    LAContext *myContext = [[LAContext alloc] init];
    // 這個(gè)屬性是設(shè)置指紋輸入失敗之后的彈出框的選項(xiàng)
    myContext.localizedFallbackTitle = @"忘記密碼";

    NSError *authError = nil;
    NSString *myLocalizedReasonString = @"請(qǐng)按住Home鍵完成驗(yàn)證";
    // MARK: 判斷設(shè)備是否支持指紋識(shí)別
    if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError])
    {
        [myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:myLocalizedReasonString reply:^(BOOL success, NSError * _Nullable error) {
            if(success)
            {
                NSLog(@"指紋認(rèn)證成功");

                weakSelf.helper.isAppCurrentLoginState = YES;

                weakSelf.logoutBtnAction.hidden = NO;
                weakSelf.userInfo.text = @"仁伯安";
            }
            else
            {
                weakSelf.helper.isAppCurrentLoginState = NO;
                NSLog(@"指紋認(rèn)證失敗走哺,%@",error.description);

                NSLog(@"%ld", (long)error.code); // 錯(cuò)誤碼 error.code
                switch (error.code)
                {
                    case LAErrorAuthenticationFailed: // Authentication was not successful, because user failed to provide valid credentials
                    {
                        NSLog(@"授權(quán)失敗"); // -1 連續(xù)三次指紋識(shí)別錯(cuò)誤
                    }
                        break;
                    case LAErrorUserCancel: // Authentication was canceled by user (e.g. tapped Cancel button)
                    {
                        NSLog(@"用戶取消驗(yàn)證Touch ID"); // -2 在TouchID對(duì)話框中點(diǎn)擊了取消按鈕

                    }
                        break;
                    case LAErrorUserFallback: // Authentication was canceled, because the user tapped the fallback button (Enter Password)
                    {
                        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                            NSLog(@"用戶選擇輸入密碼,切換主線程處理"); // -3 在TouchID對(duì)話框中點(diǎn)擊了輸入密碼按鈕
                        }];

                    }
                        break;
                    case LAErrorSystemCancel: // Authentication was canceled by system (e.g. another application went to foreground)
                    {
                        NSLog(@"取消授權(quán)哲虾,如其他應(yīng)用切入丙躏,用戶自主"); // -4 TouchID對(duì)話框被系統(tǒng)取消,例如按下Home或者電源鍵
                    }
                        break;
                    case LAErrorPasscodeNotSet: // Authentication could not start, because passcode is not set on the device.

                    {
                        NSLog(@"設(shè)備系統(tǒng)未設(shè)置密碼"); // -5
                    }
                        break;
                    case LAErrorTouchIDNotAvailable: // Authentication could not start, because Touch ID is not available on the device
                    {
                        NSLog(@"設(shè)備未設(shè)置Touch ID"); // -6
                    }
                        break;
                    case LAErrorTouchIDNotEnrolled: // Authentication could not start, because Touch ID has no enrolled fingers
                    {
                        NSLog(@"用戶未錄入指紋"); // -7
                    }
                        break;

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0
                    case LAErrorTouchIDLockout: //Authentication was not successful, because there were too many failed Touch ID attempts and Touch ID is now locked. Passcode is required to unlock Touch ID, e.g. evaluating LAPolicyDeviceOwnerAuthenticationWithBiometrics will ask for passcode as a prerequisite 用戶連續(xù)多次進(jìn)行Touch ID驗(yàn)證失敗束凑,Touch ID被鎖晒旅,需要用戶輸入密碼解鎖,先Touch ID驗(yàn)證密碼
                    {
                        NSLog(@"Touch ID被鎖汪诉,需要用戶輸入密碼解鎖"); // -8 連續(xù)五次指紋識(shí)別錯(cuò)誤废恋,TouchID功能被鎖定,下一次需要輸入系統(tǒng)密碼
                    }
                        break;
                    case LAErrorAppCancel: // Authentication was canceled by application (e.g. invalidate was called while authentication was in progress) 如突然來(lái)了電話扒寄,電話應(yīng)用進(jìn)入前臺(tái)鱼鼓,APP被掛起啦");
                    {
                        NSLog(@"用戶不能控制情況下APP被掛起"); // -9
                    }
                        break;
                    case LAErrorInvalidContext: // LAContext passed to this call has been previously invalidated.
                    {
                        NSLog(@"LAContext傳遞給這個(gè)調(diào)用之前已經(jīng)失效"); // -10
                    }
                        break;
#else
#endif
                    default:
                    {
                        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                            NSLog(@"其他情況,切換主線程處理");
                        }];
                        break;
                    }
                }
            }
        }];
    }
    else
    {
        NSLog(@"設(shè)備不支持指紋");
        NSLog(@"%ld", (long)authError.code);
        weakSelf.helper.isAppCurrentLoginState = NO;
        switch (authError.code)
        {
            case LAErrorTouchIDNotEnrolled:
            {
                NSLog(@"Authentication could not start, because Touch ID has no enrolled fingers");
                break;
            }
            case LAErrorPasscodeNotSet:
            {
                NSLog(@"Authentication could not start, because passcode is not set on the device");
                break;
            }
            default:
            {
                NSLog(@"TouchID not available");
                break;
            }
        }
    }
}

大致效果:

錄屏圖.gif

Demo GitHub下載鏈接: EVNTouchIDDemo.git该编,如果有用迄本,給個(gè)Star......

本文已在版權(quán)印備案,如需轉(zhuǎn)載請(qǐng)?jiān)诎鏅?quán)印獲取授權(quán)课竣。
獲取版權(quán)

參考文獻(xiàn):
【1】iOS security guide;
【2】Apple Objective-C;
【3】Apple Swift API.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嘉赎,一起剝皮案震驚了整個(gè)濱河市置媳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌公条,老刑警劉巖拇囊,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異靶橱,居然都是意外死亡寥袭,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門(mén)抓韩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)纠永,“玉大人鬓长,你說(shuō)我怎么就攤上這事谒拴。” “怎么了涉波?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵英上,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我啤覆,道長(zhǎng)苍日,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任窗声,我火速辦了婚禮相恃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘笨觅。我一直安慰自己拦耐,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布见剩。 她就那樣靜靜地躺著杀糯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪苍苞。 梳的紋絲不亂的頭發(fā)上固翰,一...
    開(kāi)封第一講書(shū)人閱讀 49,730評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音羹呵,去河邊找鬼骂际。 笑死,一個(gè)胖子當(dāng)著我的面吹牛冈欢,可吹牛的內(nèi)容都是我干的方援。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼涛癌,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼犯戏!你這毒婦竟也來(lái)了送火?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤先匪,失蹤者是張志新(化名)和其女友劉穎种吸,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體呀非,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡坚俗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了岸裙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片猖败。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖降允,靈堂內(nèi)的尸體忽然破棺而出恩闻,到底是詐尸還是另有隱情,我是刑警寧澤剧董,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布幢尚,位于F島的核電站,受9級(jí)特大地震影響翅楼,放射性物質(zhì)發(fā)生泄漏尉剩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一毅臊、第九天 我趴在偏房一處隱蔽的房頂上張望理茎。 院中可真熱鬧,春花似錦管嬉、人聲如沸皂林。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)式撼。三九已至,卻和暖如春求厕,著一層夾襖步出監(jiān)牢的瞬間著隆,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工呀癣, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留美浦,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓项栏,卻偏偏與公主長(zhǎng)得像浦辨,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子沼沈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 簡(jiǎn)述: 在類似支付寶為首的應(yīng)用以及各種理財(cái)?shù)壬婕板X(qián)財(cái)對(duì)安全性要求較高的應(yīng)用中流酬,目前普遍對(duì)關(guān)鍵數(shù)據(jù)都做了安全訪問(wèn)限制...
    C_HPY閱讀 2,939評(píng)論 0 18
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,727評(píng)論 25 707
  • 姨夫走后芽腾,有人說(shuō)是姨母的解脫旦装,有人說(shuō)這是命中注定的一劫。 他們的臉上有著對(duì)逝者逝去的追憶摊滔,可更多的讓我感受到的...
    被記起的閱讀 1,237評(píng)論 4 4
  • xib 中的 背景圖含长,不顯示問(wèn)題券腔。 其他元素都寫(xiě)好了伏穆,再加入拘泞。 刪除 約束,用坐標(biāo)枕扫,顯示陪腌。 然后添加約束。也顯示 ...
    plantAtree_dAp閱讀 777評(píng)論 0 0
  • 假期已過(guò)兩天半,勞心勞神到現(xiàn)在参滴。 不像某人腦簡(jiǎn)單强岸,不嫌別人說(shuō)他呆。 成天呲牙咧嘴笑砾赔,日子過(guò)得挺自在蝌箍。 前天昨天和今...
    黯黯紅塵一路相伴閱讀 259評(píng)論 1 2