IOS 8 关于 Touch ID
一、什么是Touch ID?
Touch ID是在iPhone 5s后的设备上出现的指纹识别。Apple在IOS 8中开放给第三方APP使用。 可以使用 Touch ID 来验证用户的身份,用户经验证后才能访问你 app 中的部分或全部内容。指纹数据将受到保护,不会被 iOS 或其他 app 存取。另外即将推出的Apple pay也是与Touch ID紧密相关的。
二、比较适合哪些应用场景?
涉及到个⼈私密性信息较强的应⽤(银⾏账号密码等)
优点:相对于以往的密码验证更安全,方便;
缺点:当前每台设备最多设置5个Touch ID,重启手机需要重新输入密码。
三、如何使用?
1.验证Touch ID是否可用,即当前设备是否支持Touch ID,且用户是否在设置中设置了一个Touch ID
- (void)canEvaluatePolicy { LAContext *context = [[LAContext alloc] init]; __block NSString *msg; NSError *error; BOOL success; // test if we can evaluate the policy, this test will tell us if Touch ID is available and enrolled success = [context canEvaluatePolicy: LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]; if (success) { msg =[NSString stringWithFormat:NSLocalizedString(@"TOUCH_ID_IS_AVAILABLE", nil)]; } else { msg =[NSString stringWithFormat:NSLocalizedString(@"TOUCH_ID_IS_NOT_AVAILABLE", nil)]; } [super printResult:self.textView message:msg]; }
2.验证
- (void)evaluatePolicy { LAContext *context = [[LAContext alloc] init]; __block NSString *msg; // show the authentication UI with our reason string [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:NSLocalizedString(@"UNLOCK_ACCESS_TO_LOCKED_FATURE", nil) reply: ^(BOOL success, NSError *authenticationError) { if (success) { msg =[NSString stringWithFormat:NSLocalizedString(@"EVALUATE_POLICY_SUCCESS", nil)]; } else { msg = [NSString stringWithFormat:NSLocalizedString(@"EVALUATE_POLICY_WITH_ERROR", nil), authenticationError.localizedDescription]; } [self printResult:self.textView message:msg]; }]; }
支持自定义密码验证:
- (void)evaluatePolicy2 { LAContext *context = [[LAContext alloc] init]; __block NSString *msg; // set text for the localized fallback button context.localizedFallbackTitle = NSLocalizedString(@"TOUCH_ID_FALLBACK",nil); // show the authentication UI with our reason string [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:NSLocalizedString(@"UNLOCK_ACCESS_TO_LOCKED_FATURE", nil) reply: ^(BOOL success, NSError *authenticationError) { if (success) { msg =[NSString stringWithFormat:NSLocalizedString(@"EVALUATE_POLICY_SUCCESS", nil)]; } else { msg = [NSString stringWithFormat:NSLocalizedString(@"EVALUATE_POLICY_WITH_ERROR", nil), authenticationError.localizedDescription]; } [self printResult:self.textView message:msg]; }]; }
四、KeyChain 验证
说到Touch ID就必须提Keychain,系统提供给APP存放密码的”数据库“。一般我们将密码存在APP 的独立存储中,当用户删除APP后其密码也就一并删除了,用Keychain可以将用户的密码长久保存。以前获取keychain中的密码需要输入设备的密码,有了Touch ID后就可以更安全快捷的获取密码。另外,⾃⼰的程序只能访问⾃⼰的keychain,相同bundlekeychain,从⽽实现程序间可以共同访问⼀些数
据。
旧的未使用Touch ID的方式添加密码到Keychain:
NSDictionary *attributes = @{ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, (__bridge id)kSecAttrService: @"SampleService", (__bridge id)kSecValueData: [@"SECRET_PASSWORD_TEXT" dataUsingEncoding:NSUTF8StringEncoding], (__bridge id)kSecUseNoAuthenticationUI: @YES, // (__bridge id)kSecAttrAccessControl: (__bridge_transfer id)sacObject }; dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ OSStatus status = SecItemAdd((__bridge CFDictionaryRef)attributes, nil); NSString *msg = [NSString stringWithFormat:NSLocalizedString(@"SEC_ITEM_ADD_STATUS", nil), [self keychainErrorToString:status]]; [self printResult:self.textView message:msg]; });
使用Touch ID的 方式:
NSDictionary *attributes = @{ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, (__bridge id)kSecAttrService: @"SampleService", (__bridge id)kSecValueData: [@"SECRET_PASSWORD_TEXT" dataUsingEncoding:NSUTF8StringEncoding], (__bridge id)kSecUseNoAuthenticationUI: @YES, (__bridge id)kSecAttrAccessControl: (__bridge_transfer id)sacObject }; dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ OSStatus status = SecItemAdd((__bridge CFDictionaryRef)attributes, nil); NSString *msg = [NSString stringWithFormat:NSLocalizedString(@"SEC_ITEM_ADD_STATUS", nil), [self keychainErrorToString:status]]; [self printResult:self.textView message:msg]; });
删除keychain中的密码:
- (void)deleteItemAsync { NSDictionary *query = @{ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, (__bridge id)kSecAttrService: @"SampleService" }; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ OSStatus status = SecItemDelete((__bridge CFDictionaryRef)(query)); NSString *msg = [NSString stringWithFormat:NSLocalizedString(@"SEC_ITEM_DELETE_STATUS", nil), [self keychainErrorToString:status]]; [super printResult:self.textView message:msg]; }); }
更新KeyChain中的密码:
- (void)updateItemAsync { NSDictionary *query = @{ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, (__bridge id)kSecAttrService: @"SampleService", (__bridge id)kSecUseOperationPrompt: @"Authenticate to update your password" }; NSDictionary *changes = @{ (__bridge id)kSecValueData: [@"UPDATED_SECRET_PASSWORD_TEXT" dataUsingEncoding:NSUTF8StringEncoding] }; dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)changes); NSString *msg = [NSString stringWithFormat:NSLocalizedString(@"SEC_ITEM_UPDATE_STATUS", nil), [self keychainErrorToString:status]]; [super printResult:self.textView message:msg]; }); }
获取Keychain中的密码:
- (void)copyMatchingAsync { NSDictionary *query = @{ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, (__bridge id)kSecAttrService: @"SampleService", (__bridge id)kSecReturnData: @YES, (__bridge id)kSecUseOperationPrompt: NSLocalizedString(@"AUTHENTICATE_TO_ACCESS_SERVICE_PASSWORD", nil) }; dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ CFTypeRef dataTypeRef = NULL; NSString *msg; OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)(query), &dataTypeRef); if (status == errSecSuccess) { NSData *resultData = ( __bridge_transfer NSData *)dataTypeRef; NSString * result = [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding]; msg = [NSString stringWithFormat:NSLocalizedString(@"RESULT", nil), result]; } else { msg = [NSString stringWithFormat:NSLocalizedString(@"SEC_ITEM_COPY_MATCHING_STATUS", nil), [self keychainErrorToString:status]]; } [self printResult:self.textView message:msg]; }); }
Demo地址:https://developer.apple.com/library/ios/samplecode/KeychainTouchID/Introduction/Intro.html#//apple_ref/doc/uid/TP40014530-Intro-DontLinkElementID_2