Keychain Service et Swift 3
Bonjour à tous,
J'ai un souci avec une de mes applications depuis le passage à Xcode 8 et Swift 3.
En effet j'utilise Keychain service et plus précisément le code suivant récupéré sur un blog pour stocker l'identifiant et le mot de passe de l'utilisateur.
import UIKit
import Security
// Identifiers
let serviceIdentifier = "MyService"
let userAccount = "authenticatedUser"
let accessGroup = "MyService"
// Arguments for the keychain queries
let kSecClassValue = NSString(format: kSecClass) as NSString
let kSecAttrAccountValue = NSString(format: kSecAttrAccount) as NSString
let kSecValueDataValue = NSString(format: kSecValueData) as NSString
let kSecClassGenericPasswordValue = NSString(format: kSecClassGenericPassword) as NSString
let kSecAttrServiceValue = NSString(format: kSecAttrService) as NSString
let kSecMatchLimitValue = NSString(format: kSecMatchLimit) as NSString
let kSecReturnDataValue = NSString(format: kSecReturnData) as NSString
let kSecMatchLimitOneValue = NSString(format: kSecMatchLimitOne) as NSString
class KeychainService: NSObject {
/**
* Exposed methods to perform queries.
* Note: feel free to play around with the arguments
* for these if you want to be able to customise the
* service identifier, user accounts, access groups, etc.
*/
class func saveToken(_ token: NSString) {
self.save(serviceIdentifier as NSString, data: token)
}
class func loadToken() -> NSString? {
let token = self.load(service: serviceIdentifier as NSString)
return token as! NSString?
}
class func deleteToken(_ token: String) {
self.delete(token)
}
class func clearToken() {
self.clear()
}
fileprivate class func delete(_ key: String) -> Bool
{
let query = [
(kSecClass as String) : kSecClassGenericPassword,
(kSecAttrAccount as String) : key
] as [String : Any]
return SecItemDelete(query as CFDictionary) == noErr
}
fileprivate class func clear() -> Bool
{
let query = [
(kSecClass as String): kSecClassGenericPassword
]
return SecItemDelete(query as CFDictionary) == noErr
}
fileprivate class func save(_ service: NSString, data: NSString) {
let dataFromString: Data = data.data(using: String.Encoding.utf8.rawValue, allowLossyConversion: false)!
// Instantiate a new default keychain query
let keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, userAccount, dataFromString], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecValueDataValue])
// Delete any existing items
SecItemDelete(keychainQuery as CFDictionary)
// Add the new keychain item
// var status: OSStatus = SecItemAdd(keychainQuery as CFDictionaryRef, nil)
SecItemAdd(keychainQuery as CFDictionary, nil)
}
fileprivate class func load(service: NSString) -> AnyObject? {
// Instantiate a new default keychain query
// Tell the query to return a result
// Limit our results to one item
let keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, userAccount, kCFBooleanTrue, kSecMatchLimitOneValue], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecReturnDataValue, kSecMatchLimitValue])
var dataTypeRef :Unmanaged<AnyObject>?
// Search for the keychain items
// let status: OSStatus = SecItemCopyMatching(keychainQuery, &dataTypeRef)
let status: OSStatus = withUnsafeMutablePointer(to: &dataTypeRef) { SecItemCopyMatching(keychainQuery as CFDictionary, UnsafeMutablePointer($0)) }
let opaque = dataTypeRef?.toOpaque()
var contentsOfKeychain: NSString?
if let op = opaque {
let retrievedData = Unmanaged<NSData>.fromOpaque(op).takeUnretainedValue()
// Convert the data retrieved from the keychain into a string
contentsOfKeychain = NSString(data: retrievedData as Data, encoding: String.Encoding.utf8.rawValue)
} else {
print("Nothing was retrieved from the keychain. Status code \(status)")
}
return contentsOfKeychain
}
}
Au niveau de l'instruction
let status: OSStatus = withUnsafeMutablePointer(to: &dataTypeRef) { SecItemCopyMatching(keychainQuery as CFDictionary, UnsafeMutablePointer($0)) }
j'ai le message :
'init' is unavailable: use 'withMemoryRebound(to:capacity:_)' to temporarily view memory as another layout-compatible type.
Auriez-vous la solution pour remédier à ce problème, d'avance merci.
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Sur Swift 3 ils ont changé pas mal de chose et notamment l'introduction du type UnsafeRawPointer : https://swift.org/migration-guide/se-0107-migrate.html
Tu dois utiliser une des 3 méthodes qu'ils mentionnent sur ce même lien pour migrer de UnsafePointer<Void> à UnsafeRawPointer.
Par exemple on aurait quelque chose comme ceci :
Merci,
j'ai testé le code suivant :
Mais j'ai l'erreur suivante :
le sujet est trop pointu pour moi !
merci de votre aide.
Je pense que je vais supprimer l'utilisation de code étant donné que je ne trouve pas la solution.
Un conseil à me donner sur ce que je pourrais utiliser à la place pour stocker username et password.
Merci.
https://github.com/nicklockwood/FXKeychain
Je l'utilise, j'en suis très satisfait. ça permet d'utiliser le Keychain comme un bête dictionnaire.