You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firebase Apple登录无用户新增及代码适配问题求助

Apple登录Firebase无用户新增+方法参数报错排查

问题概述

按Firebase官方指南配置SignInWithApple按钮后,点击按钮Firebase控制台未新增用户;同时指南中的OAuthProvider.appleCredential方法在Xcode中提示无该参数,只能改用OAuthProvider.credential方法,怀疑此改动导致问题,附上代码请求排查:

官方指南中无法使用的代码

// Initialize a Firebase credential, including the user's full name.
let credential = OAuthProvider.appleCredential(withIDToken: idTokenString,
                                               rawNonce: nonce,
                                               fullName: appleIDCredential.fullName)
// Sign in with Firebase.

实际使用的登录按钮代码

//Mark:apple sign in button
SignInWithAppleButton(onRequest: { request in
    request.requestedScopes = [.fullName, .email]
    let nonce = fireAuth.randomNonceString()
    fireAuth.currentNonce = nonce
    request.nonce = fireAuth.sha256(nonce)
}, onCompletion: { result in
    if case.failure(let failure) = result {
        errorMessage = failure.localizedDescription
    }
    else if case.success(let success) = result {
        if let appleIDCredential = success.credential as? ASAuthorizationAppleIDCredential {
            guard let nonce = fireAuth.currentNonce else {
                fatalError("Invalid state: a login callback was received, but no login request was sent.")
            }
            guard let appleIDToken = appleIDCredential.identityToken else {
                print("Unable to fetch identity token.")
                return
            }
            guard let idTokenString = String(data: appleIDToken, encoding: .utf8) else {
                print("Unable to serialise token string from data: \(appleIDToken.debugDescription)")
                return
            }
            // Initialize a Firebase credential
            let credential = OAuthProvider.credential(withProviderID:"apple.com",
                                                      idToken: idTokenString,
                                                      rawNonce: nonce)
            // Sign in with Firebase.
            Auth.auth().signIn(with: credential){(authResult,err) in
                if let error = err{
                    print(error.localizedDescription)
                    return
                }
            }
            
            //User successfully logged into firebase...
            print("Logged In Success")
        }
    }
})
.frame(width:150,height:40)

FireAuth工具类代码

class FireAuth: ObservableObject {
 //   static let share = FireAuth()
    
    @State var currentNonce: String? = String()

   
    init() {}
    
    // Apple Sign In
    func randomNonceString(length: Int = 32) -> String {
      precondition(length > 0)
      var randomBytes = [UInt8](repeating: 0, count: length)
      let errorCode = SecRandomCopyBytes(kSecRandomDefault, randomBytes.count, &randomBytes)
      if errorCode != errSecSuccess {
        fatalError(
          "Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)"
        )
      }

      let charset: [Character] =
        Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._")

      let nonce = randomBytes.map { byte in
        // Pick a random character from the set, wrapping around if needed.
        charset[Int(byte) % charset.count]
      }

      return String(nonce)
    }
    
    //Hashing function using CryptoKit
    func sha256(_ input: String) -> String {
      let inputData = Data(input.utf8)
      let hashedData = SHA256.hash(data: inputData)
      let hashString = hashedData.compactMap {
        String(format: "%02x", $0)
      }.joined()

      return hashString
    }
}

核心问题排查与修复

1. OAuthProvider.appleCredential方法不存在的原因

该方法是Firebase Auth SDK旧版本API,新版本已统一使用OAuthProvider.credential(withProviderID:idToken:rawNonce:),你的替换是正确的,此改动不是用户未新增的直接原因。

2. 用户未新增的关键问题

(1)currentNonce属性修饰符错误

@State仅适用于SwiftUI视图结构体,在ObservableObject类中需使用@Published,否则nonce无法正确传递,导致Firebase验证失败:

// 错误写法
@State var currentNonce: String? = String()

// 正确写法
@Published var currentNonce: String?

(2)异步登录逻辑错误

你在Auth.auth().signIn(with:credential)的闭包外部打印"Logged In Success",但Firebase登录是异步操作,只有闭包执行完成才代表登录成功,当前写法会导致即使登录失败也会打印成功,无法准确判断状态:

// 错误写法
Auth.auth().signIn(with: credential){(authResult,err) in
    if let error = err{
        print(error.localizedDescription)
        return
    }
}
print("Logged In Success")

// 正确写法
Auth.auth().signIn(with: credential){(authResult,err) in
    if let error = err{
        print(error.localizedDescription)
        return
    }
    // 登录成功后才执行后续逻辑
    print("Logged In Success")
    if let user = authResult?.user {
        print("用户UID:\(user.uid)")
    }
}

(3)额外验证点

  • 确认Firebase控制台已开启Apple登录,Team ID、Bundle ID、签名证书配置完全正确;
  • 使用真实设备测试(模拟器可能存在Apple登录权限问题);
  • 检查signIn闭包中的authResult是否返回用户信息,确认验证流程是否完成;
  • 打印request.nonce和sha256(nonce)的结果,确保两者一致(Firebase要求nonce哈希值为SHA-256小写十六进制字符串)。

3. 修正后的关键代码片段

FireAuth类修正

class FireAuth: ObservableObject {
    static let shared = FireAuth() // 改为单例,方便全局调用
    
    @Published var currentNonce: String?

    init() {}
    
    func randomNonceString(length: Int = 32) -> String {
        precondition(length > 0)
        var randomBytes = [UInt8](repeating: 0, count: length)
        let errorCode = SecRandomCopyBytes(kSecRandomDefault, randomBytes.count, &randomBytes)
        if errorCode != errSecSuccess {
            fatalError("Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)")
        }

        let charset: [Character] = Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._")
        let nonce = randomBytes.map { charset[Int(byte) % charset.count] }
        return String(nonce)
    }
    
    func sha256(_ input: String) -> String {
        let inputData = Data(input.utf8)
        let hashedData = SHA256.hash(data: inputData)
        return hashedData.compactMap { String(format: "%02x", $0) }.joined()
    }
}

登录按钮闭包修正

SignInWithAppleButton(onRequest: { request in
    request.requestedScopes = [.fullName, .email]
    let nonce = FireAuth.shared.randomNonceString()
    FireAuth.shared.currentNonce = nonce
    request.nonce = FireAuth.shared.sha256(nonce)
}, onCompletion: { result in
    switch result {
    case .failure(let failure):
        print(failure.localizedDescription)
    case .success(let success):
        guard let appleIDCredential = success.credential as? ASAuthorizationAppleIDCredential else {
            print("无效的凭证类型")
            return
        }
        guard let nonce = FireAuth.shared.currentNonce else {
            fatalError("无效状态:未找到nonce")
        }
        guard let appleIDToken = appleIDCredential.identityToken else {
            print("无法获取身份令牌")
            return
        }
        guard let idTokenString = String(data: appleIDToken, encoding: .utf8) else {
            print("无法序列化令牌字符串")
            return
        }
        
        let credential = OAuthProvider.credential(withProviderID:"apple.com",
                                                  idToken: idTokenString,
                                                  rawNonce: nonce)
        
        Auth.auth().signIn(with: credential) { authResult, error in
            if let error = error {
                print("Firebase登录错误:\(error.localizedDescription)")
                return
            }
            // 登录成功处理
            if let user = authResult?.user {
                print("登录用户UID:\(user.uid)")
                print("用户邮箱:\(user.email ?? "未获取到邮箱")")
                // 此处可添加UI跳转或用户信息同步逻辑
            }
        }
    }
})
.frame(width:150,height:40)

内容的提问来源于stack exchange,提问作者Tracy9988 Xu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 05:52:11