【发布时间】:2021-10-10 10:42:34
【问题描述】:
目前,我有四种不同的提供商方法可以在我的应用中登录/创建帐户:
- 电子邮件和密码
- 谷歌
- 脸书
- 微软
当用户第一次通过其中一个提供商登录(或通过电子邮件和密码创建帐户)时,我会自动创建一个带有附加信息的 用户文档在云火库中。这是我的一个提供商(电子邮件和密码)的问题:
当用户使用提供商“电子邮件和密码”创建帐户时,他可以选择他/她喜欢的任何电子邮件,因此也可以使用 Google 或 Microsoft 电子邮件并提供错误的附加信息(错误的名称等)。然后,此错误信息将存储在用户创建帐户后我创建的 user-document 中。
如果上述用户未验证他的电子邮件并通过 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()
}
Google 代码
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!!))
}
【问题讨论】:
标签: android firebase firebase-authentication