钥匙串访问控制(带密码后备的 TouchID)

Keychain 允许使用特殊的 SecAccessControl 属性保存项目,这样只有在用户使用 Touch ID 进行身份验证后才能从 Keychain 获取项目(如果允许这样的回退,则允许使用密码)。仅通知应用程序验证是否成功,整个 UI 由 iOS 管理。

首先,应创建 SecAccessControl 对象:

迅速

let error: Unmanaged<CFError>?

guard let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, .userPresence, &error) else {
    fatalError("Something went wrong")
}

接下来,使用 kSecAttrAccessControl 键将其添加到字典中(与其他示例中使用的 kSecAttrAccessible 键互斥):

迅速

var dictionary = [String : Any]()

dictionary[kSecClass as String] = kSecClassGenericPassword
dictionary[kSecAttrLabel as String] = "com.me.myapp.myaccountpassword" as CFString
dictionary[kSecAttrAccount as String] = "My Name" as CFString
dictionary[kSecValueData as String] = "new_password!!".data(using: .utf8) as! CFData
dictionary[kSecAttrAccessControl as String] = accessControl

并像以前一样保存它:

迅速

let lastResultCode = SecItemAdd(query as CFDictionary, nil)

要访问存储的数据,只需查询 Keychain 以获取密钥。Keychain Services 将向用户显示身份验证对话框并返回数据或 nil,具体取决于是否提供了合适的指纹或匹配的密码。

(可选)可以指定提示字符串:

迅速

var query = [String: Any]()

query[kSecClass as String] = kSecClassGenericPassword
query[kSecReturnData as String] = kCFBooleanTrue
query[kSecAttrAccount as String] = "My Name" as CFString
query[kSecAttrLabel as String] = "com.me.myapp.myaccountpassword" as CFString
query[kSecUseOperationPrompt as String] = "Please put your fingers on that button" as CFString

var queryResult: AnyObject?
let status = withUnsafeMutablePointer(to: &queryResult) {
    SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))
}

如果用户拒绝,取消或未通过授权,请注意 status 将成为 err

迅速

if status == noErr {
    let password = String(data: queryResult as! Data, encoding: .utf8)!
    print("Password: \(password)")
} else {
    print("Authorization not passed")
}