一、什么是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,相同bundle的程序通过设置group可以互相共享同组的keychain,从⽽实现程序间可以共同访问⼀些数
据。
旧的未使用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