简体   繁体   English

在 Firebase 中组织组 Swift 上的身份验证

[英]Organizing groups in Firebase Authentication on Swift

I am using Firebase authentication on Swift in Xcode.我在 Xcode 中的 Swift 上使用 Firebase 身份验证。 I want to create "groups" for the user login so that certain users will have access to certain data.我想为用户登录创建“组”,以便某些用户可以访问某些数据。 For example, in my app, I want basketball players on the basketball team to only have access to the basketball stats.例如,在我的应用程序中,我希望篮球队中的篮球运动员只能访问篮球统计数据。 Does anyone know what this is called in Firebase and how to do it?有谁知道这在 Firebase 中叫什么以及怎么做?

As mentioned, the user for the authentication (Auth user) is just the user for the authentication, it does not contain much more information.如前所述,身份验证用户(Auth user)只是身份验证用户,它不包含更多信息。 Please see the attached screenshot from Firebase (Authentication):请参阅 Firebase(身份验证)的随附屏幕截图:

验证用户

That is the reason why we have to add a new User struct (in the users collection) which provides all these kind of information (could be name, age, groups of something.... whatever).这就是为什么我们必须添加一个新的User结构(在users集合中),它提供所有这些类型的信息(可能是姓名、年龄、某些东西的组......等等)。 The user document needs a reference to the Auth user.用户文档需要对 Auth 用户的引用。 In the example I am using the user uid (@frank-van-puffelen is that a common way to use the uid or does it cause safety relevant issues?)在示例中,我使用的是用户 uid(@frank-van-puffelen 是使用 uid 的常用方法还是会导致安全相关问题?)

在此处输入图像描述

One side note, since we only get the entire documents and sometimes a user could have some private data that must not be available for others, it may make sense to split the struct into PublicUser and PrivateUser.附带说明一下,由于我们只获取整个文档,并且有时用户可能拥有一些对其他人不可用的私有数据,因此将结构拆分为 PublicUser 和 PrivateUser 可能是有意义的。

Anyway, for this example, let's create a User struct in swift无论如何,对于这个例子,让我们在 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"
}

Now, let's do the magic with the UserViewModel which contains the functions we call to work with Firebase (Firestore), eg signUp (here we are talking about the Auth user), signIn (Auth user again) or createNewUser (here it is our new user struct):现在,让我们用 UserViewModel 来做魔术,它包含我们调用的函数来使用 Firebase (Firestore),例如 signUp(这里我们谈论的是 Auth 用户)、signIn(再次验证用户)或 createNewUser(这里是我们的新用户)用户结构):

UserViewModel.swift 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)")
        }
    }
    
    // FOR TESTING: 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)
        }
    }
    
}

Now you have 2 options to signUp (the Auth user) AND create a new user (based on the new user struct):现在您有 2 个选项来注册(身份验证用户)并创建一个新用户(基于新用户结构):

  1. You have 2 separate views, on the first view, the user signs up, that creates the Auth user.您有 2 个单独的视图,在第一个视图上,用户注册,创建 Auth 用户。 On the second view, which is only available after signing up, the user can add data like name, group or whatever you want.在第二个视图中,仅在注册后可用,用户可以添加名称、组或任何您想要的数据。 (I'd prefer this option) (我更喜欢这个选项)

  2. You handle everything in one view.您可以在一个视图中处理所有事情。 You are holding all necessary data, call the signUp function and when you get the completion response, you call the function to create the user.您持有所有必要的数据,调用注册 function 并在收到完成响应时调用 function 来创建用户。

One last thing, since you don't get that information from Auth.auth(), if you want to be able to change these data, you'll have to fetch the user data for that specific user from the Firestore database.最后一件事,由于您无法从 Auth.auth() 中获取该信息,因此如果您希望能够更改这些数据,则必须从 Firestore 数据库中获取该特定用户的用户数据。 Of course you can save these information as values to UserDefaults (storage) while you create a new user, later you can save that information when the user logs in.当然,您可以在创建新用户时将这些信息作为值保存到 UserDefaults(存储),稍后您可以在用户登录时保存该信息。

Best, Sebastian最好的,塞巴斯蒂安

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM