基于Firebase的账号密码登录APP,如何判断用户登录状态
Hey there! Let's break down how to check the user's login status after closing your LoginViewController, given your Firebase Realtime Database setup:
1. Use Firebase Auth's Built-in State Listener (Highly Recommended)
While you're maintaining a loggedIn field in your Users node, Firebase Auth already handles user session persistence and state tracking out of the box. You can combine this with your custom node to double-check the status:
import FirebaseAuth import FirebaseDatabase // Add this listener in your AppDelegate, SceneDelegate, or a global state manager class Auth.auth().addStateDidChangeListener { auth, user in if let currentUser = user { // User is authenticated via Firebase Auth, now verify your custom `loggedIn` status let userRef = Database.database().reference().child("Users").child(currentUser.displayName ?? currentUser.uid) // Replace with your actual username key if you're using that instead of UID userRef.observeSingleEvent(of: .value) { snapshot in guard let userData = snapshot.value as? [String: Any], let loggedInStatus = userData["loggedIn"] as? String, loggedInStatus == "true" else { // Custom status doesn't match, treat as logged out // Redirect to LoginViewController here return } // User is fully logged in, proceed to main app flow } } else { // No authenticated user, redirect to login } }
2. Directly Check Your Custom loggedIn Field
If you want to rely solely on your Users node's loggedIn attribute, you'll need to persist the current username locally (e.g., via UserDefaults) when login succeeds, then fetch the remote status when needed:
One-Time Check (Great for App Launch)
import FirebaseDatabase // Fetch the saved username first guard let currentUsername = UserDefaults.standard.string(forKey: "currentLoggedInUsername") else { // No saved username = user isn't logged in return } // Pull the user's data from Firebase let userRef = Database.database().reference().child("Users").child(currentUsername) userRef.observeSingleEvent(of: .value) { snapshot in guard let userData = snapshot.value as? [String: Any], let loggedIn = userData["loggedIn"] as? String, loggedIn == "true" else { // User isn't marked as logged in in the database // Clear local saved data and redirect to login UserDefaults.standard.removeObject(forKey: "currentLoggedInUsername") return } // User is logged in, continue with main app }
Real-Time Listener (For Live Status Updates)
If you need to react immediately if the loggedIn status changes (e.g., from another device), use a real-time observer:
guard let currentUsername = UserDefaults.standard.string(forKey: "currentLoggedInUsername") else { return } let userRef = Database.database().reference().child("Users").child(currentUsername) userRef.observe(.value) { snapshot in guard let userData = snapshot.value as? [String: Any], let loggedInStatus = userData["loggedIn"] as? String else { return } if loggedInStatus == "true" { // Maintain logged-in state } else { // Status changed to logged out - clear local data and redirect UserDefaults.standard.removeObject(forKey: "currentLoggedInUsername") // Navigate back to LoginViewController } }
3. Combine Local Persistence with Remote Validation
For faster initial checks, save the login status locally when login succeeds, then verify against Firebase to ensure consistency:
// When login succeeds in LoginViewController: UserDefaults.standard.set(currentUsername, forKey: "currentLoggedInUsername") UserDefaults.standard.set("true", forKey: "localLoginStatus") UserDefaults.standard.synchronize() // When checking status later: let isLocallyLoggedIn = UserDefaults.standard.string(forKey: "localLoginStatus") == "true" guard let username = UserDefaults.standard.string(forKey: "currentLoggedInUsername"), isLocallyLoggedIn else { // Local state says logged out, redirect to login return } // Verify with Firebase to confirm let userRef = Database.database().reference().child("Users").child(username) userRef.observeSingleEvent(of: .value) { snapshot in guard let userData = snapshot.value as? [String: Any], let remoteStatus = userData["loggedIn"] as? String, remoteStatus == "true" else { // Remote status doesn't match local - update local state UserDefaults.standard.set("false", forKey: "localLoginStatus") // Redirect to login return } // Both local and remote confirm login, proceed }
Important Notes:
- Secure Your Database Rules: Make sure only the authenticated user can modify their own
loggedInfield. Example rule:"Users": { "$username": { ".write": "auth != null && auth.token.name == $username" } } - Clean Up on Logout: When the user logs out, set
loggedInto"false"in Firebase, and clear all local persisted data.
内容的提问来源于stack exchange,提问作者mn497

