【问题标题】:Firebase delete account along with Database and Storage on iOSFirebase 删除帐户以及 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 语句中处理。因此,如果会话旧,此错误会阻止删除帐户。

标签: ios swift firebase-realtime-database firebase-authentication firebase-storage


【解决方案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://stackoverflow.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)
    
    
            }
    

    【讨论】:

      猜你喜欢
      • 2019-10-19
      • 2020-12-29
      • 2018-07-09
      • 2014-03-13
      • 2020-10-21
      • 1970-01-01
      • 1970-01-01
      • 2016-07-30
      相关资源
      最近更新 更多