在苹果钥匙串中存储和读取密码的简单方法?

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

我想要一种使用 swift5 在苹果钥匙串中存储和读取密码的简单方法 iOS

有关钥匙串的 Apple 文档有点混乱 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)
}

应该打印 12345678 但打印 Optional("f9dd6069-4e51-4c18-9dc6-7db6254271e3")

您将密码作为字符串存储在钥匙串中。我将修改 storeKeychain() 方法

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
}

检查它是否有效。