import Foundation import Security /// 用于安全存储和检索敏感信息(如令牌)的 Keychain 帮助类 public class KeychainHelper { // Keychain 键名 private enum KeychainKey: String { case accessToken = "com.memorywake.accessToken" case refreshToken = "com.memorywake.refreshToken" } /// 保存访问令牌到 Keychain public static func saveAccessToken(_ token: String) -> Bool { return save(token, for: .accessToken) } /// 从 Keychain 获取访问令牌 public static func getAccessToken() -> String? { return get(for: .accessToken) } /// 保存刷新令牌到 Keychain public static func saveRefreshToken(_ token: String) -> Bool { return save(token, for: .refreshToken) } /// 从 Keychain 获取刷新令牌 public static func getRefreshToken() -> String? { return get(for: .refreshToken) } /// 删除所有存储的令牌 public static func clearTokens() { delete(for: .accessToken) delete(for: .refreshToken) } // MARK: - 私有方法 private static func save(_ string: String, for key: KeychainKey) -> Bool { guard let data = string.data(using: .utf8) else { return false } let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: key.rawValue, kSecValueData as String: data ] // 先删除已存在的项目 SecItemDelete(query as CFDictionary) // 添加新项目 let status = SecItemAdd(query as CFDictionary, nil) return status == errSecSuccess } private static func get(for key: KeychainKey) -> String? { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: key.rawValue, kSecReturnData as String: true, kSecMatchLimit as String: kSecMatchLimitOne ] var dataTypeRef: AnyObject? let status = SecItemCopyMatching(query as CFDictionary, &dataTypeRef) guard status == errSecSuccess, let data = dataTypeRef as? Data else { return nil } return String(data: data, encoding: .utf8) } private static func delete(for key: KeychainKey) { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: key.rawValue ] SecItemDelete(query as CFDictionary) } }