iOS TouchID驗證和Keychain結合使用

1.TouchID的簡單實現

首先先導入LocalAuthentication/LocalAuthentication.h頭文件
使用TouchID前先檢測TouchID是否可用,然後再調用

LAContext *context = [[LAContext alloc] init];
BOOL success = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:nil];
if(success){
    NSLog(@"can use");
}else{
    NSLog(@"can`t user ");
}
//在驗證TouchID可用的情況下使用
LAContext *context = [[LAContext alloc] init];
context.localizedFallbackTitle = @"自定義標題";

[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:@"爲什麼使用TouchID寫這裏" reply:^(BOOL success, NSError * _Nullable error) {

    if(success){
        //指紋驗證成功
    }else{
        switch (error.code) {
             case LAErrorUserFallback:{
                NSLog(@"用戶選擇輸入密碼");
                break;
             }
            case LAErrorAuthenticationFailed:{
                NSLog(@"驗證失敗");
                break;
            }
            case LAErrorUserCancel:{
                NSLog(@"用戶取消");
                break;
            }
            case LAErrorSystemCancel:{
                NSLog(@"系統取消");
                break;
            }
            //以下三種情況如果提前檢測TouchID是否可用就不會出現
            case LAErrorPasscodeNotSet:{
                break;
            }
            case LAErrorTouchIDNotAvailable:{
                break;
            }
            case LAErrorTouchIDNotEnrolled:{
                break;
            }

            default:
               break;
            }
        }
}];

這裏寫圖片描述
這裏寫圖片描述

2.Keychain簡單使用

Keychain大體的保存使用流程如下圖
這裏寫圖片描述
下面是鑰匙串的增刪改查

//要像是串中增加一條
/*
 kSecClass                   //類型
 kSecAttrGeneric             //作爲唯一標識
 kSecAttrService             //所具有的服務
 kSecAttrAccount             //用戶名
 kSecValueData               //保存密碼對應的key
 kSecAttrModificationDate    //修改日期
 */
NSDictionary *attributes = @{(id)kSecClass: (id)kSecClassGenericPassword,
                             (id)kSecAttrGeneric:[NSBundle mainBundle].bundleIdentifier,
                             (id)kSecAttrService: @"SampleService",
                             (id)kSecAttrAccount:userName,
                             (id)kSecValueData:[password dataUsingEncoding:NSUTF8StringEncoding],
                             (id)kSecAttrModificationDate:[NSDate date],
                             };

OSStatus status =  SecItemAdd((__bridge CFDictionaryRef)attributes, nil);
if(status == errSecSuccess){
    return YES;
}else{
    NSLog(@"%@",[self keychainErrorToString:status]);
}

//修改
NSDictionary *attribute = @{(id)kSecClass: (id)kSecClassGenericPassword,
                            (id)kSecAttrGeneric:[NSBundle mainBundle].bundleIdentifier,
                            (id)kSecAttrService: @"SampleService",
                            (id)kSecAttrAccount:userName,
                            };

NSDictionary *changeDic = @{(id)kSecValueData:[password dataUsingEncoding:NSUTF8StringEncoding],
                            (id)kSecAttrModificationDate:[NSDate date]
                            };

OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)attribute, (__bridge CFDictionaryRef)changeDic);
if(status == errSecSuccess){
    return YES;
}else{
    NSLog(@"%@",[self keychainErrorToString:status]);
}

//查詢
NSDictionary *attributes = @{(id)kSecClass: (id)kSecClassGenericPassword,
                             (id)kSecAttrGeneric:[NSBundle mainBundle].bundleIdentifier,
                             (id)kSecAttrAccount:userName,
                             (id)kSecAttrService: @"SampleService",
                             (id)kSecReturnData: @YES,
                             (id)kSecReturnAttributes:@YES,
                             (id)kSecMatchLimit:(id)kSecMatchLimitOne,
                            };

CFMutableDictionaryRef outDictionary = nil;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)attributes, (CFTypeRef *)&outDictionary);
if(status == errSecSuccess){

    NSDictionary *result = (__bridge_transfer NSDictionary *)outDictionary;
    NSData *passWordData = result[(id)kSecValueData];
    if(passWordData){
        return [[NSString alloc] initWithData:passWordData encoding:NSUTF8StringEncoding];
    }
}else{
    NSLog(@"%@",[self keychainErrorToString:status]);
}

//刪除
NSDictionary *attributes = @{(id)kSecClass: (id)kSecClassGenericPassword,
                        (id)kSecAttrGeneric:[NSBundle mainBundle].bundleIdentifier,
                        (id)kSecAttrService: @"SampleService",
                        (id)kSecAttrAccount:userName
                        };

OSStatus status = SecItemDelete((__bridge CFDictionaryRef)attributes);
if(status == errSecSuccess){
    return YES;
}else{
    NSLog(@"%@",[self keychainErrorToString:status]);
}

看好多APP都有指紋登錄,長時間沒有登錄的話指紋登錄會失效
我想了一下實現思路
1. APP內部有一個指紋登錄開關,打開開關
2. 將賬號和密碼存儲到鑰匙串,將當前賬號存儲到沙盒中
3. 下次登錄時根據沙盒存儲的賬號到鑰匙串中查詢密碼和修改時間
4. 如果鑰匙串的修改時間和當前時間的差值不超過你的預設範圍就可以用鑰匙串中密碼登錄,如果超除了預設範圍就需要密碼輸入,登錄成功後更新鑰匙串的密碼和修改時間
5. 如果鑰匙串中數據的密碼錯誤(可能在其他機器中修改過密碼等),則需要輸入密碼,登陸成功後更新鑰匙串
6. 如果關閉指紋登錄則需要將鑰匙串刪除

TouchID和Keychain的簡單使用Demo地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章