使用 LAContext 和 touchIDAuthenticationAllowableReuseDuration 获取钥匙串项

Posted

技术标签:

【中文标题】使用 LAContext 和 touchIDAuthenticationAllowableReuseDuration 获取钥匙串项【英文标题】:Get keychain item with LAContext and touchIDAuthenticationAllowableReuseDuration 【发布时间】:2016-06-21 16:11:53 【问题描述】:

我正在尝试将touchIDAuthenticationAllowableReuseDuration 的功能添加到我的应用程序中。我使用 Touch ID 对用户进行身份验证以进入应用程序,同时从钥匙串中恢复项目。在我尝试添加之前没有问题,它总是要求输入 Touch ID,或者如果设备密码不可用。现在到目前为止,我已经设法让它做同样的事情,并且在指定的超时时间内打开应用程序时,它不会显示应有的 Touch ID 提示,如果我所做的只是验证用户我已经完成了,但是我遇到的问题是我还想从钥匙串中恢复一个项目,并且当提示被成功绕过时,但是一旦我调用SecItemCopyMatching(…),我就无法取回该项目,而是不断收到errSecAuthFailed

我在网上到处都看过,我发现的最好的东西是 Apple 的示例代码 KeychainTouchID,但同样,它不会同时进行身份验证和从钥匙串中获取项目,我试过了将其添加到他们的代码中,我也不断收到相同的错误。

以前有没有人尝试过这样的事情?你是怎么让它工作的?这是我现在的代码:

SecAccessControlRef sacObject = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlTouchIDAny, nil);

NSString *localizedReason = NSLocalizedString(@"Authenticate to access app", nil);

LAContext *context = [[LAContext alloc] init];
context.touchIDAuthenticationAllowableReuseDuration = 5;

[context evaluateAccessControl:sacObject operation:LAAccessControlOperationUseItem localizedReason:localizedReason reply:^(BOOL success, NSError *error) 
    if (success) 
        NSDictionary *query = @(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
                                (__bridge id)kSecAttrService: PASSCODE_KEY,
                                (__bridge id)kSecReturnData: @YES,
                                (__bridge id)kSecUseOperationPrompt: localizedReason,
                                (__bridge id)kSecUseAuthenticationUI: (__bridge id)kSecUseAuthenticationUIAllow,
                                (__bridge id)kSecAttrAccessControl: (__bridge_transfer id)sacObject,
                                (__bridge id)kSecUseAuthenticationContext: context
                                ;

        CFTypeRef dataTypeRef = NULL;

        OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)(query), &dataTypeRef);
        // This works when using Touch ID / passcode, but I get errSecAuthFailed when the prompt isn't shown because of the reuse duration.
        if (status == errSecSuccess) 
            NSData *resultData = (__bridge_transfer NSData *)dataTypeRef;
            NSString *result = [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
            self.recoveredString = result;

         else 
            self.recoveredString = @"";
        
     else 
        self.recoveredString = @"";
        CFRelease(sacObject);
    
];

【问题讨论】:

我们的团队遇到了完全相同的问题。你找到解决方案了吗? 遗憾的是还没找到解决办法 我在重用和访问钥匙串方面遇到了同样的问题。但是,在调用 SecItemCopyMatching 时,总是会提示我输入 touchid。您对 (__bridge id)kSecUseAuthenticationUI: (__bridge id)kSecUseAuthenticationUIAllow 的使用应该是多余的,因为它是默认值。你找到解决办法了吗? 【参考方案1】:

不要每次都创建 LAContext 对象。只需抓住evaluateAccessControl 成功的LAContext 对象。这样你就不需要设置touchIDAuthenticationAllowableReuseDuration。如果您在 evaluateAccessControl 已经成功的 LAContext 对象上调用 evaluateAccessControl,那么会立即成功调用回复回调,而不会要求用户再次进行身份验证

当您希望用户再次进行身份验证时,只需使 LAContext 对象无效。

【讨论】:

以上是关于使用 LAContext 和 touchIDAuthenticationAllowableReuseDuration 获取钥匙串项的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 touchIDAuthenticationAllowableReuseDuration

用户拒绝使用生物特征时的生物特征类型

如何在横向模式下使用 TouchID?

IOS 指纹识别的简单使用

iOS 中 Touch ID得使用方法

我如何观察用户何时使用生物识别技术对应用程序进行身份验证?