import Foundation import Security //let username = "user1" // Сохраняем токены //KeychainService.shared.save("access_token_value", forKey: "access_token", service: username) //KeychainService.shared.save("refresh_token_value", forKey: "refresh_token", service: username) // Получаем токены //let accessToken = KeychainService.shared.get(forKey: "access_token", service: username) //let refreshToken = KeychainService.shared.get(forKey: "refresh_token", service: username) // получение всех пользователей //let users = KeychainService.shared.getAllServices() //print("Все пользователи: \(users)") // Удаление всех пользователей //KeychainService.shared.deleteAll() // удаление по одному //KeychainService.shared.delete(forKey: "access_token", service: username) //KeychainService.shared.delete(forKey: "refresh_token", service: username) class KeychainService { static let shared = KeychainService() private init() {} func save(_ value: String, forKey key: String, service: String) { guard let data = value.data(using: .utf8) else { return } let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrService as String: service, // ключ группировки kSecAttrAccount as String: key, kSecValueData as String: data ] SecItemDelete(query as CFDictionary) let status = SecItemAdd(query as CFDictionary, nil) if status != errSecSuccess { print("Error saving to Keychain: \(status)") } } func get(forKey key: String, service: String) -> String? { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrService as String: service, kSecAttrAccount as String: key, kSecReturnData as String: true, kSecMatchLimit as String: kSecMatchLimitOne ] var dataTypeRef: AnyObject? let status = SecItemCopyMatching(query as CFDictionary, &dataTypeRef) if status == errSecSuccess, let data = dataTypeRef as? Data, let value = String(data: data, encoding: .utf8) { return value } return nil } func getAllServices() -> [String] { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecReturnAttributes as String: true, kSecMatchLimit as String: kSecMatchLimitAll ] var result: AnyObject? let status = SecItemCopyMatching(query as CFDictionary, &result) guard status == errSecSuccess, let items = result as? [[String: Any]] else { return [] } // Собираем все уникальные service (username) var services = Set() for item in items { if let service = item[kSecAttrService as String] as? String { services.insert(service) } } return Array(services) } func delete(forKey key: String, service: String) { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrService as String: service, kSecAttrAccount as String: key ] SecItemDelete(query as CFDictionary) } /// Удалить все записи Keychain, сохранённые этим приложением func deleteAll() { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword ] let status = SecItemDelete(query as CFDictionary) if status != errSecSuccess && status != errSecItemNotFound { print("Error deleting all Keychain items: \(status)") } } }