如前所述,身份验证用户(Auth user)只是身份验证用户,它不包含更多信息。请参阅 Firebase(身份验证)随附的屏幕截图:
这就是为什么我们必须添加一个新的用户结构(在用户集合),它提供了所有这些类型的信息(可以是姓名、年龄、某事物的组......无论如何)。用户文档需要对 Auth 用户的引用。在示例中,我使用的是用户 uid(@frank-van-puffelen 是使用 uid 的常用方法还是会导致安全相关问题?)
附带说明一下,由于我们只获取整个文档,并且有时用户可能拥有一些对其他人不可用的私有数据,因此将结构拆分为 PublicUser 和 PrivateUser 可能是有意义的。
无论如何,对于这个例子,让我们在 swift 中创建一个 User 结构
用户
//
// User.swift
// Firebase User
//
// Created by Sebastian Fox on 18.08.22.
//
import Foundation
import SwiftUI
import Firebase
struct User: Codable, Identifiable, Hashable {
var id: String?
var name: String
var group: SportType
init(name: String, group: SportType, id: String?) {
self.id = id
self.name = name
self.group = group
}
init?(document: QueryDocumentSnapshot) {
let data = document.data()
guard let name = data["name"] as? String else {
return nil
}
guard let group = data["group"] as? SportType else {
return nil
}
id = document.documentID
self.name = name
self.group = group
}
enum CodingKeys: String, CodingKey {
case id
case name
case group
}
}
extension User: Comparable {
static func == (lhs: User, rhs: User) -> Bool {
return lhs.id == rhs.id
}
static func < (lhs: User, rhs: User) -> Bool {
return lhs.name < rhs.name
}
}
// I also create an enum with sort types, this is not necessarily part of the User struct. To load it to the Firestone database it must be codable.
enum SportType: String, Codable, CaseIterable {
case basektball = "Basketball"
case baseball = "Baseball"
case soccer = "Soccer"
case chess = "Chess"
case noSport = "No Sport"
}
现在,让我们使用 UserViewModel 来实现魔法,它包含我们调用的用于使用 Firebase (Firestore) 的函数,例如signUp(这里我们讨论的是 Auth 用户)、signIn(再次验证用户)或 createNewUser(这里是我们的新用户结构):
UserViewModel.swift
//
// UserViewModel.swift
// Firebase User
//
// Created by Sebastian Fox on 18.08.22.
//
import Foundation
import FirebaseFirestore
import Firebase
import FirebaseFirestoreSwift
class UsersViewModel: ObservableObject {
let db = Firestore.firestore()
// Published and saved to local device
@Published var users = [User]()
// Sign Up
func signUp(email: String, password: String, completion: @escaping (Bool, String)->Void) {
Auth.auth().createUser(withEmail: email, password: password) { authResult, error in
// ERROR AND SUCCESS HANDLING
if error != nil {
// ERROR HANDLING
print(error?.localizedDescription as Any)
completion(false, "ERROR")
}
// SUCCESS HANDLING
completion(true, authResult?.user.uid ?? "")
}
}
// Sign In
func signIn(email: String, password: String, completion: @escaping (Bool)->Void) {
Auth.auth().signIn(withEmail: email, password: password) { (authResult, error) in
// ERROR AND SUCCESS HANDLING
if error != nil {
// ERROR HANDLING
print(error?.localizedDescription as Any)
completion(true)
}
// SUCCESS HANDLING
completion(true)
}
}
// Sign Out
func signOut() {
try! Auth.auth().signOut()
}
// Create new user
func createNewUser(name: String, group: SportType, id: String) {
do {
let newUser = User(name: name, group: group, id: id)
try db.collection("users").document(newUser.id!).setData(from: newUser) { _ in
print("User \(name) created")
}
} catch let error {
print("Error writing user to Firestore: \(error)")
}
}
// Get a list of all users
func fetchAllUsers(_ completion: @escaping (Bool) ->Void) {
self.users = []
db.collection("users").addSnapshotListener { (querySnapshot, error) in
guard let documents = querySnapshot?.documents else {
print("No documents")
return
}
self.users = documents.map { queryDocumentSnapshot -> User in
let data = queryDocumentSnapshot.data()
let id = data["id"] as? String ?? ""
let name = data["name"] as? String ?? ""
let group = data["group"] as? String ?? ""
return User(name: name, group: SportType(rawValue: group) ?? .noSport, id: id)
}
completion(true)
}
}
}
现在您有 2 个选项来注册(身份验证用户)并创建一个新用户(基于新用户结构):
-
您有 2 个单独的视图,在第一个视图上,用户注册,创建 Auth 用户。在第二个视图中,仅在注册后可用,用户可以添加名称、组或任何您想要的数据。 (我更喜欢这个选项)
-
您可以在一个视图中处理所有事情。您持有所有必要的数据,调用 signUp 函数,当您收到完成响应时,调用该函数来创建用户。
最后一件事,由于您无法从 Auth.auth() 中获取该信息,因此如果您希望能够更改这些数据,则必须从 Firestore 数据库中获取该特定用户的用户数据。当然,您可以在创建新用户时将这些信息作为值保存到 UserDefaults(存储),稍后您可以在用户登录时保存该信息。
最好的,塞巴斯蒂安