Firebase 删除帐户以及 iOS 上的数据库和存储

Posted

技术标签:

【中文标题】Firebase 删除帐户以及 iOS 上的数据库和存储【英文标题】:Firebase delete account along with Database and Storage on iOS 【发布时间】:2018-11-13 09:18:47 【问题描述】:

我正在尝试实现在 ios 上删除当前用户帐户的功能。帐户删除工作正常,但问题是我在删除帐户时无法从数据库和存储中删除帐户的数据。

"currentUser.delete" 删除帐户,但我认为没有身份验证可以从数据库和存储中删除其数据。权限被拒绝消息显示在日志中。运行此功能后,我在 Firebase 控制台身份验证页面中看到该帐户已消失,但数据库和存储中的数据仍然存在。

这是删除帐户的正确方法吗?

在删除帐户之前,我尝试从数据库和存储中删除数据。但是,如果会话超过 5 分钟,Firebase 会要求重新进行身份验证。重新登录会在再次执行帐户删除之前向用户显示空数据,因此这是一种误导且非常混乱。

请告诉我如何在删除帐户时删除数据。

private func deleteAccount() 
  guard let currentUser = Auth.auth().currentUser else 
    return print("user not logged in")
  

  currentUser.delete  error in
    if error == nil 
      // 1. Delete currentUser's data from Database. Permission denied
      // 2. Delete currentUser's data from Storage. Permission denied
      // present login screen (welcome page)
      self.presentLoginScreen()
     else 
      guard let errorCode = AuthErrorCode(rawValue: error!._code) else  return 

      if errorCode == AuthErrorCode.requiresRecentLogin 
        self.showMessage("Please re-authenticate to delete your account.", type: .error)

        do 
          try Auth.auth().signOut()
          self.presentLoginScreen()
         catch 
          print("There was a problem logging out")
        
      
    
  

【问题讨论】:

在删除帐户之前删除数据是从客户端实现此目的的唯一方法。但是,当您说“我在删除帐户之前尝试从数据库和存储中删除数据。但是,如果会话超过 5 分钟,Firebase 会要求重新进行身份验证”,但我不明白您的意思。我不明白这里有什么问题。如果用户帐户被删除,那几乎就结束了,对吧? 嗨,Doug,如果用户的会话超过 5 分钟,他会返回欢迎页面。但是随后该用户将看到空数据,并且必须转到设置页面再次执行帐户删除。我认为这很令人困惑。 1. 用户进入设置页面删除账户。 2. 他被要求重新认证并自动返回欢迎页面。 3.他再次登录,但数据全部消失,帐户仍然存在。 4.他必须去设置页面再次删除帐户。这不是很奇怪吗? 您正在删除该帐户。在那种情况下,我希望一切都会重置。会话年龄与任何事情无关。这里有什么事情你没有分享吗? 不需要用UID识别用户相关数据吗?因此,您只需创建一个函数来删除包含/与该特定 UID 相关的内容。 我相信会话年龄确实很重要。如果它超过 5 分钟,我会收到一个错误,在 else 语句中处理。因此,如果会话旧,此错误会阻止删除帐户。 【参考方案1】:

斯威夫特 5 | Firebase 8.11.0

要解决您提到的问题(在删除实际用户之前删除数据并可能得到AuthErrorCode.requiresRecentLogin 错误),您可以使用DispatchGroup 并检查lastSignInDate,就像这样(只需调用@ 987654325@):

let deleteDataGroup = DispatchGroup()

func deleteUserProcess() 
    guard let currentUser = Auth.auth().currentUser else  return 
    deleteUserData(user: currentUser)
    // Call deleteUser only when all data has been deleted
    deleteDataGroup.notify(queue: .main) 
        self.deleteUser(user: currentUser)
    

/// Remove data from Database & Storage
func deleteUserData(user currentUser: User) 
    // Check if `currentUser.delete()` won't require re-authentication
    if let lastSignInDate = currentUser.metadata.lastSignInDate,
        lastSignInDate.minutes(from: Date()) >= -5 
        deleteDataGroup.enter()
        Database.database().reference().child(userId).removeValue  error, _ in
            if let error = error  print(error) 
            self.deleteDataGroup.leave()
        
        // Delete folders from Storage isn't possible,
        // so list and run over all files to delete each one independently
        deleteDataGroup.enter()
        Storage.storage().reference().child(userId).listAll  list, error in
            if let error = error  print(error) 
            list.items.forEach( file in
                self.deleteDataGroup.enter()
                file.delete  error in
                    if let error = error  print(error) 
                    self.deleteDataGroup.leave()
                
            )
            deleteDataGroup.leave()
        
    


/// Delete user
func deleteUser(user currentUser: User) 
    currentUser.delete  error in
        if let error = error 
            if AuthErrorCode(rawValue: error._code) == .requiresRecentLogin 
                reauthenticate()
             else 
                // Another error occurred
            
            return
        

        // Logout properly
        try? Auth.auth().signOut()
        GIDSignIn.sharedInstance.signOut()
        LoginManager().logOut()

        // The user has been deleted successfully
        // TODO: Redirect to the login UI
    


func reauthenticate() 
    // TODO: Display some UI to get credential from the user
    let credential = ... // Complete from https://***.com/a/38253448/8157190
    Auth.auth().currentUser?.reauthenticate(with: credential)  _, error in
        if let error = error 
            print(error)
            return
        

        // Reload user (to update metadata.lastSignInDate)
        Auth.auth().currentUser?.reload  error in
            if let error = error 
                print(error)
                return
            
            // TODO: Dismiss UI
            // Call `deleteUserProcess()` again, this time it will delete the user
            deleteUserProcess()
        
    

小步舞曲功能可以添加到Date的扩展中(感谢Leo Dabus):

extension Date 
    /// Returns the amount of minutes from another date
    func minutes(from date: Date) -> Int 
        return Calendar.current.dateComponents([.minute], from: date, to: self).minute ?? 0
    

【讨论】:

【参考方案2】:

您可以先删除您的特定用户,并通过其 UID 删除其值,然后您可以删除用户并在删除后将他带到根视图控制器或登录屏幕。

// removing user data from firebase and its specific user id 
         let user = Auth.auth().currentUser
        user?.delete  error in
          if let error = error 
            // An error happened.
            print(error.localizedDescription)
           else 
            Database.database().reference().child("users").child(user?.uid ?? "").removeValue()
            self.navigationController?.popToRootViewController(animated: true)
            // Account deleted and logout user
//            do 
//                try Auth.auth().signOut()
                // take you to root
//                self.navigationController?.popToRootViewController(animated: true)


        

【讨论】:

以上是关于Firebase 删除帐户以及 iOS 上的数据库和存储的主要内容,如果未能解决你的问题,请参考以下文章

Firebase 删除用户问题

当我在firebase上删除他的帐户时如何从应用程序中注销用户?

如何使用 Angular 从 Firebase 中删除用户帐户

电话身份验证创建新帐户并断开 Firebase 上的链接

有没有办法从 Firebase 中删除有关用户的所有数据?

从 Firebase 存储中删除文件会导致崩溃