如何在Swift中使用Firebase实现用户持久登录?
Hey there! 作为Swift新手能搞定登录注册已经超棒啦😉,关于应用关闭后保持登录状态,核心就是持久化存储用户的登录凭证,下面给你一步步拆解具体操作:
一、登录成功后保存登录凭证
当用户登录请求成功返回后,你需要把能证明用户身份的信息存起来——最常用的是服务器返回的accessToken,再配合一个“是否已登录”的标记。
1. 轻量场景用UserDefaults(适合存非敏感标记)
如果只是记录登录状态(比如一个布尔值),可以用UserDefaults,但绝对不要用它存token、密码这类敏感信息,因为它是明文存在沙盒里的,不安全:
// 登录成功后调用这个方法 func saveLoginState(token: String) { // 存登录标记 UserDefaults.standard.set(true, forKey: "isUserLoggedIn") // 如果只是临时过渡,也可以存token,但强烈建议用下面的Keychain存敏感信息 // UserDefaults.standard.set(token, forKey: "tempAccessToken") UserDefaults.standard.synchronize() // 现在系统会自动同步,但手动调用更稳妥 }
2. 敏感信息用Keychain(推荐方案)
Keychain是系统提供的安全存储容器,专门用来存密码、token这类敏感数据,即使App被卸载,数据也会保留(除非用户手动清除)。这里给你一个封装好的工具类示例:
import Security class KeychainManager { static let shared = KeychainManager() private init() {} // 保存数据到Keychain func save(key: String, data: Data) -> OSStatus { let query = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: key, kSecValueData as String: data ] as [String: Any] // 先删除旧数据(避免重复存储) SecItemDelete(query as CFDictionary) // 添加新数据 return SecItemAdd(query as CFDictionary, nil) } // 从Keychain读取数据 func fetch(key: String) -> Data? { let query = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: key, kSecReturnData as String: kCFBooleanTrue!, kSecMatchLimit as String: kSecMatchLimitOne ] as [String: Any] var result: AnyObject? let status = SecItemCopyMatching(query as CFDictionary, &result) return status == noErr ? result as? Data : nil } // 删除Keychain中的数据 func delete(key: String) -> OSStatus { let query = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: key ] as [String: Any] return SecItemDelete(query as CFDictionary) } } // 使用示例:登录成功后保存token if let tokenData = "服务器返回的accessToken".data(using: .utf8) { let status = KeychainManager.shared.save(key: "userAccessToken", data: tokenData) if status == noErr { print("Token保存成功!") // 同时用UserDefaults存登录标记,方便快速判断状态 UserDefaults.standard.set(true, forKey: "isUserLoggedIn") } }
二、App启动时检查登录状态
在App启动的入口(比如UIKit的AppDelegate,或者SwiftUI的App结构体),读取之前保存的凭证,判断是否直接进入主页面还是登录页面:
UIKit 示例
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { checkLoginStatus() return true } private func checkLoginStatus() { let isLoggedIn = UserDefaults.standard.bool(forKey: "isUserLoggedIn") guard isLoggedIn else { // 未登录,跳转到登录页 window?.rootViewController = LoginViewController() return } // 读取Keychain里的token并校验有效性 if let tokenData = KeychainManager.shared.fetch(key: "userAccessToken"), let token = String(data: tokenData, encoding: .utf8) { // 这里可以请求服务器校验token是否过期 validateToken(token: token) { isValid in DispatchQueue.main.async { if isValid { // token有效,进入主页面 self.window?.rootViewController = MainTabBarController() } else { // token过期,跳转到登录页 self.window?.rootViewController = LoginViewController() } } } } else { // 凭证丢失,强制登录 window?.rootViewController = LoginViewController() } } // 模拟校验token的方法 private func validateToken(token: String, completion: @escaping (Bool) -> Void) { // 这里调用服务器接口校验token // 示例:假设接口返回有效 completion(true) }
SwiftUI 示例
@main struct MyApp: App { @State private var shouldShowMainView = false init() { let isLoggedIn = UserDefaults.standard.bool(forKey: "isUserLoggedIn") if isLoggedIn { // 校验token有效性 if let tokenData = KeychainManager.shared.fetch(key: "userAccessToken"), let token = String(data: tokenData, encoding: .utf8) { // 调用服务器接口校验token,这里简化处理 shouldShowMainView = true } } } var body: some Scene { WindowGroup { if shouldShowMainView { MainView() } else { LoginView() } } } }
三、退出登录时清理凭证
当用户点击退出登录,一定要把所有登录相关的凭证彻底删除:
func handleLogout() { // 清除UserDefaults的登录标记 UserDefaults.standard.set(false, forKey: "isUserLoggedIn") UserDefaults.standard.removeObject(forKey: "isUserLoggedIn") // 清除Keychain里的token KeychainManager.shared.delete(key: "userAccessToken") // 跳转到登录页面 // UIKit: window?.rootViewController = LoginViewController() // SwiftUI: shouldShowMainView = false }
额外提醒
- Token过期处理:服务器返回的token一般有过期时间,建议在每次请求接口前检查token是否过期,或者监听接口返回的“token失效”错误,及时跳转到登录页面。
- 不要存密码:永远不要把用户的明文密码存在本地,登录成功后只存服务器返回的token即可。
- 多设备同步:如果你的App支持多设备登录,可能需要处理token被挤掉的情况,这时候依赖服务器的返回逻辑来触发重新登录。
内容的提问来源于stack exchange,提问作者PinkySweater97
相关产品推荐
相关产品推荐

