iOS Keychain Access Control (TouchID avec retour de mot de passe)


Exemple

Le trousseau permet de sauvegarder des éléments avec un attribut spécial SecAccessControl qui permettra d'obtenir un élément du trousseau uniquement après que l'utilisateur aura été authentifié avec Touch ID (ou un mot de passe si un tel retour est autorisé). App est seulement averti si l'authentification a réussi ou non, l'interface utilisateur entière est gérée par iOS.

Tout d'abord, l'objet SecAccessControl doit être créé:

Rapide

let error: Unmanaged<CFError>?

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

Ensuite, ajoutez-la au dictionnaire avec la clé kSecAttrAccessControl (qui est mutuellement exclusive avec la clé kSecAttrAccessible que vous avez utilisée dans d'autres exemples):

Rapide

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

Et sauvegardez-le comme vous l'avez fait auparavant:

Rapide

let lastResultCode = SecItemAdd(query as CFDictionary, nil)

Pour accéder aux données stockées, interrogez simplement Keychain pour obtenir une clé. Keychain Services présentera la boîte de dialogue d'authentification à l'utilisateur et retournera des données ou des données nulles selon que l'empreinte digitale appropriée a été fournie ou que le code d'accès a été apparié.

En option, une chaîne d'invite peut être spécifiée:

Rapide

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))
}

Faites attention que le status sera err si l'utilisateur a refusé, annulé ou échoué l'autorisation.

Rapide

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