簡體   English   中英

Firebase:如何檢查用戶身份驗證是否被其他提供商覆蓋?

[英]Firebase: How to check if a user auth was overriden by another provider?

目前,我有四種不同的提供商方法可以在我的應用程序中登錄/創建帳戶:

  • Email 和密碼
  • 谷歌
  • Facebook
  • 微軟

當用戶第一次通過其中一個提供商登錄時(或通過 email 和密碼創建帳戶),我會自動在 cloud-firestore 中創建一個包含附加信息的用戶文檔 我的其中一位提供商(電子郵件和密碼)出現了問題:

當用戶使用提供商“電子郵件和密碼”創建帳戶時,他可以選擇他/她喜歡的任何 email,因此也可以使用 Google 或 Microsoft email 並提供錯誤的附加信息(錯誤的名稱等)。 一旦用戶創建了他的帳戶,這個錯誤的信息就會存儲在我創建的用戶文檔中。

如果上述用戶隨后未驗證他的 email 並通過 Google 或 Microsoft 提供商登錄,舊的“電子郵件和密碼”提供商將被覆蓋,但不是我之前創建的錯誤用戶文檔

我的問題是:有沒有辦法讓觀察者或知道一個提供者被另一個提供者覆蓋,因此也覆蓋了錯誤的用戶文檔

通用代碼

// Check if user-document already exists, so it does not get overridden 
// when logging in via Google, Microsoft or Facebook-auth
private suspend fun isUserRegistered(): Boolean {
    val document = dbFirestore.collection(FIREBASE_USER_BASE_PATH).document(dbAuth.currentUser!!.uid).get().await()
    return document.exists()
}

private suspend fun createUserIfNotExist(user: UserNetworkEntity) {
    if (isUserRegistered()) return
    createUserAccount(dbAuth.currentUser!!.uid, user)
}

// Function to check whether user is verified and delete old doc if not verified 
// Here the user-data and the created user-doc will be verified via firebase-admin-sdk
private suspend fun callUserOnCheck(email: String): HttpsCallableResult? {
    return dbFunctions
        .getHttpsCallable(FUNCTION_USER_ON_CHECK_EMAIL)
        .call(hashMapOf<String, String?>("email" to email))
        .await()
}

谷歌代碼

override fun signInWithGoogle(account: GoogleSignInAccount): Flow<LoginStateEvent> = flow {
    val credential = GoogleAuthProvider.getCredential(account.idToken, null)

    // Delete old doc if not verified. Getting email from GoogleSignInAccount
    // IMPORTANT: We have to check the old document here, before calling dbAuth.signInWithCredential()
    // because #signInWithCredential() would override the old email-provider
    val email = account.email!!
    callUserOnCheck(email)

    dbAuth.signInWithCredential(credential).await()

    createUserIfNotExist(UserNetworkEntity(fullName = fullName))
}

代碼 Facebook

override fun signInWithFacebook(): Flow<LoginStateEvent> = flow {
    val result = fLoginManager.registerMCallback(callbackManager)

    val credential = FacebookAuthProvider.getCredential(result.accessToken.token)

    // Delete old doc if not verified. Getting email from Facebook-GraphResponse
    // IMPORTANT: We have to check the old document here, before calling dbAuth.signInWithCredential()
    // because #signInWithCredential() would override the old email-provider
    callUserOnCheckFacebook(result.accessToken)

    dbAuth.signInWithCredential(credential).await()

    createUserIfNotExist(UserNetworkEntity(fullName = dbAuth.currentUser!!.displayName!!))
}

// Function to check whether user is verified. Special case: Get Facebook email via GraphResponce 
private suspend fun callUserOnCheckFacebook(accessToken: AccessToken) {
    val email = getFacebookEmail(accessToken)
    if (email != null) callUserOnCheck(email)
}

// Get Facebook email via GraphResponce without the need to login via #signInWithCredential()
private suspend fun getFacebookEmail(accessToken: AccessToken) = suspendCancellableCoroutine<String?> { cont ->
    val callback = GraphRequest.GraphJSONObjectCallback { json, response ->
        // OnError
        response?.error?.let { cont.resumeWithException(Throwable(it.errorMessage)) }

        // OnSucess
        cont.resume(json?.optString("email"), cont::resumeWithException)
    }

    GraphRequest.newMeRequest(accessToken, callback)
}

Microsoft 代碼(如何解決 TODO?)

override fun signInWithMicrosoft(activity: Activity): Flow<LoginStateEvent> = flow {

   // TODO: Check whether old created user-doc is valid or not before calling
   // dbAuth.pendingAuthResult or ..startActivityForSignIn... as this would
   // override the old existing email-provider.
   // Question: How to get microsoft-email without calling #pendingAuthResult or #startActivityForSignIn ?
    
    val result = dbAuth.pendingAuthResult?.await() ?: dbAuth.startActivityForSignInWithProvider(
        activity,
        microsoftOAuth.build()
    ).await()

    createUserIfNotExist(UserNetworkEntity(fullName = result.user!!.displayName!!))
}

我認為您可能正在尋找fetchSignInMethodsForEmail function 您可以將此傳遞給用戶的 email,然后檢查 email 是否已與電子郵件+密碼提供商一起使用(在這種情況下,您需要清理該文檔)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM