iOS钥匙串TouchID提示两次问题解决方法

3

如果Keychain中不存在该项,我希望添加一项;如果存在,我希望更新它。 我使用 SecItemCopyMatching 进行检查,通过以下查询进行:

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

SecItemCopyMatching提示用户使用touchid/passcode。 之后,我需要更新keychain,这又会提示用户。 我可以在程序中存储一个BOOL来保存状态,但它可能与keychain中的值不同步,所以我更愿意查询keychain本身是否存在该项,但我不想让用户获得双重提示。有没有办法做到这一点?

1个回答

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接