84 lines
2.6 KiB
Swift
84 lines
2.6 KiB
Swift
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)
|
||
}
|
||
}
|