钥匙串iOS touchId提示两次

时间:2014-11-24 20:07:37

标签: ios objective-c touch-id

我想在keychain中添加一个项目(如果它不存在)或者如果它存在则更新。 我调用SecItemCopyMatching来检查项是否存在通过以下查询:

  NSDictionary *query = @{
                            (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
                            (__bridge id)kSecAttrService: @"myservice",
                            (__bridge id)kSecReturnData: @NO
                            };    

SecItemCopyMatching会提示用户输入touchid /密码。 之后我需要更新钥匙串,再次提示用户。 我可以在我的程序中存储BOOL来保存状态,但可能与钥匙串中的值不同步所以如果项目存在与否,我宁愿查询钥匙串本身,但我不希望用户获得双提示。有没有办法做到这一点?

1 个答案:

答案 0 :(得分:1)

此处的解决方法是首先调用update。除非该项目存在,否则它不会提示您。如果更新调用返回errSecItemNotFound,则添加数据。这应该只提示你一次。如果你添加一个项目,它根本不应该提示你。

class func updateData(value: NSData, forKey keyName: String) -> Bool {
    let keychainQueryDictionary: NSMutableDictionary = self.setupKeychainQueryDictionaryForKey(keyName)
    let updateDictionary = [SecValueData:value]

    let status: OSStatus = SecItemUpdate(keychainQueryDictionary, updateDictionary)

    if status == errSecSuccess {
        return true
    } else if status == errSecItemNotFound {
        return setData(value, forKey: keyName)
    } else {
        return false
    }
}

class func setData(value: NSData, forKey keyName: String) -> Bool {
    var keychainQueryDictionary: NSMutableDictionary = self.setupKeychainQueryDictionaryForKey(keyName)

    keychainQueryDictionary[SecValueData] = value

    var error:Unmanaged<CFErrorRef>?
    let sacObject = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleAfterFirstUnlock, SecAccessControlCreateFlags.UserPresence, &error)
    keychainQueryDictionary[SecAttrAccessControl] = sacObject.takeRetainedValue()

    let status: OSStatus = SecItemAdd(keychainQueryDictionary, nil)

    if status == errSecSuccess {
        return true
    } else {
        return false
    }
}

private class func setupKeychainQueryDictionaryForKey(keyName: String) -> NSMutableDictionary {
    var attributes = NSMutableDictionary()
    attributes[SecClass] = kSecClassGenericPassword as String
    attributes[SecAttrService] = "Sample Service 1"
    attributes[SecUseOperationPrompt] = "Operation prompt goes here"
    attributes[SecAttrAccount] = keyName

    return attributes
}

此代码由Jason Rendel的KeychainWrapper修改。