You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 11:52:51