简体   繁体   中英

Simple way to store and read a password in apple keychain?

I want a simple way to store and read a password in apple keychain using swift5 for iOS

Apple documentation about keychain is a little confusing https://developer.apple.com/documentation/security/keychain_services/keychain_items/adding_a_password_to_the_keychain?language=swift

struct Credentials {
    var username: String
    var password: String
}
enum KeychainError: Error {
    case noPassword
    case unexpectedPasswordData
    case unhandledError(status: OSStatus)
}
struct Credentials {
        var username: String
        var password: String
    }

private func storeKeychain(username: String, password: String)throws->Any? {
        let credentials = Credentials.init(username: username, password: password)
        let query: [String: Any] = [kSecClass as String:  kSecClassGenericPassword,
                                    kSecValueData as String: credentials.password]

        let status = SecItemAdd(query as CFDictionary, nil)
        guard status == errSecSuccess else {
            throw KeychainError.unhandledError(status: status) }

        return status
    }

private func getKeychain()throws ->String {
        let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
                                    kSecMatchLimit as String: kSecMatchLimitOne,
                                    kSecReturnAttributes as String: true,
                                    kSecReturnData as String: true]
        var item: CFTypeRef?
        let status = SecItemCopyMatching(query as CFDictionary, &item)
        guard status != errSecItemNotFound else { throw KeychainError.noPassword }
        guard status == errSecSuccess else { throw KeychainError.unhandledError(status: status) }

        guard let existingItem = item as? [String : Any],
            let passwordData = existingItem[kSecValueData as String] as? Data,
            let password = String(data: passwordData, encoding: String.Encoding.utf8),
            let account = existingItem[kSecAttrAccount as String] as? String
            else {
                throw KeychainError.unexpectedPasswordData
        }
        _ = Credentials(username: account, password: password)
        return password
    }

override func viewDidLoad() {
        super.viewDidLoad()
           let keychains = try? storeKeychain(username: "John", password: "12345678")
        let password = try? getKeychain()
        print(password)
}

Should print 12345678 but prints Optional("f9dd6069-4e51-4c18-9dc6-7db6254271e3")

You are storing password as a string inside keychain. I will modify storeKeychain() method

private func storeKeychain(username: String, password: String) throws -> Any? {
    let credentials = Credentials.init(username: username, password: password)
    let data = credentials.password.data(using: .utf8)!

// store password as data and if you want to store username
    let query: [String: Any] = [kSecClass as String:  kSecClassGenericPassword,
                                kSecAttrAccount as String: username,
                                kSecValueData as String: data]
    let status = SecItemAdd(query as CFDictionary, nil)
    guard status == errSecSuccess else {
        throw KeychainError.unhandledError(status: status) }
    return status
}

Check if it works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM