Firebase中Apple登录账号无法与其他提供商关联的问题咨询
Apple隐藏邮箱导致Firebase账号关联失败问题
主登录界面支持多提供商登录,选择对应提供商后会触发signInWithCredential函数,尝试完成登录并按需关联账号。但Apple允许用户隐藏邮箱以保护隐私,这会导致Firebase无法识别用户,进而无法将该账号与其他提供商账号关联——即便使用JWT的sub令牌作为唯一用户标识也无法解决此问题。当用户退出后使用其他提供商重新登录时,Firebase会分配新的用户ID,此时无法从同一数据库节点获取Apple用户ID,而原始用户ID在用户首次登录时已存储在数据库中。
相关实现代码
/// 异步使用给定凭证登录用户 /// - 参数: /// - credential: 用于登录用户的认证凭证 /// - appleJWTToken: Apple登录的可选JWT令牌(默认值为nil) /// - 抛出: 执行过程中出现异常时会抛出`NSError`类型的错误 /// - 返回值: 无返回值 func signInWithCredential(credential: AuthCredential, appleJWTToken: String? = nil) async throws { do { // 使用提供的凭证尝试用户认证 let authResult = try await Auth.auth().signIn(with: credential) let currentUser = authResult.user // 验证认证凭证的提供商 if credential.provider == FirebaseProviders.Apple.rawValue, let appleJWTToken = appleJWTToken { // 如果提供商是Apple,将JWT令牌存储到数据库中 try await storeJWTToken(appleJWTToken, forUser: currentUser.uid) } else if let pendingSignInData = pendingSignInData { // 如果存在待处理的凭证,将其与当前账号关联 try await linkFirebaseAccount(with: pendingSignInData.credential) } else { // 处理其他提供商的登录,必要时关联Apple账号 let isAlreadyLinked = isLinkedWithApple(forUser: currentUser.uid) let appleJWT = try await retrieveAppleJWT(forUser: currentUser.uid) if let appleJWT = appleJWT, !isAlreadyLinked { // 如果Apple JWT存在且用户尚未关联Apple账号,创建Apple凭证并关联账号 let appleCredential = OAuthProvider.credential(withProviderID: FirebaseProviders.Apple.rawValue, idToken: appleJWT, rawNonce: nil) try await linkFirebaseAccount(with: appleCredential) } // 关联其他提供商账号,例如Google与Facebook try await linkFirebaseAccount(with: credential) } } catch let error as NSError { // 处理账号冲突或登录失败相关错误 if error.code == AuthErrorCode.accountExistsWithDifferentCredential.rawValue { let email = error.userInfo[AuthErrorUserInfoEmailKey] as! String let pendingCredential = error.userInfo[AuthErrorUserInfoUpdatedCredentialKey] as! AuthCredential guard let providers = try? await Auth.auth().fetchSignInMethods(forEmail: email), let provider = providers.first else { throw SignInError.providerNotFound } pendingSignInData = PendingSignInData(email: email, credential: pendingCredential, method: provider) throw SignInError.signInConflict } else { throw SignInError.failedToSignIn(error) } } } fileprivate func linkFirebaseAccount(with credential: AuthCredential) async throws { guard let currentUser = Auth.auth().currentUser else { // 处理错误 throw SignInError.failedToLinkAccount } do { try await currentUser.link(with: credential) pendingSignInData = nil // 关联成功后清除待处理数据 } catch { // 处理错误 throw SignInError.failedToLinkAccount } }
内容的提问来源于stack exchange,提问作者David.C
相关产品推荐
相关产品推荐

