如何从应用程序强制注销Firebase身份验证用户

时间:2018-10-31 16:19:13

标签: firebase firebase-authentication firebase-admin

我有一个使用firebase auth和firebaseUI进行身份验证的项目。我已经启用了Google,Facebook和电子邮件提供商。我需要的是远程注销或禁用某些用户。

我希望用户这样做退出应用程序。我尝试在Firebase控制台中禁用用户,还使用Firebase管理SDK(https://firebase.google.com/docs/auth/admin/manage-sessions)撤消刷新令牌。

我等待了2天以上,但仍然注意到该用户已登录并且可以访问Firestore数据。

我也经历了尝试 Firebase still retrieving authData after deletion

谁能指出我做错了什么?

6 个答案:

答案 0 :(得分:4)

您也不能远程强制用户注销。任何注销都必须从用户登录的设备上进行。

一旦铸造出访问令牌,就无法撤消它。这意味着,即使您禁用了该用户的帐户,他们也可能继续拥有长达一个小时的访问权限。

如果时间太长,诀窍(正如我对所链接问题的回答中所提到的)是维护数据库(或其他位置)中被阻止用户的列表,然后根据安全规则(或其他授权层)。

例如,在实时数据库中,您可以创建被阻止用户的UID的列表:

banned_uids
  uid1: true
  uid2: true

然后使用以下命令检查您的安全规则中的内容:

".read": "auth.uid !== null && !root.child('banned_uids').child(auth.uid).exists()"

答案 1 :(得分:4)

您可以使用FCM发送消息数据以强制注销。

例如,如果用户使用android应用程序。

  1. 将FCM令牌保存在Firebase Realtime中的集合中。
  2. 在服务中配置Android客户端应用。 LINK您必须在收到带有特殊字符串的消息时强行退出。
  3. 在云功能中创建所需的触发器,以在需要用户注销时发送数据LINK

成功!

答案 2 :(得分:2)

根据您的情况,我假设您在禁用用户时需要注销用户。

使用一个全局变量存储 TokenNo (可能处于共享首选项或sqlite):

在清单中添加以下代码:

<service android:name=".YourFirebaseMessagingService">
 <intent-filter>
     <action android:name="com.google.firebase.MESSAGING_EVENT" />
 </intent-filter>
</service>

在您的

中添加以下代码
public class LogoutOntokenchange extends FirebaseMessagingService{
   @Override
   public void onNewToken (String token){
     if(TokenNo=>1){ //if tokenNo >=1 means he already logged in
       TokenNo=0;
       FirebaseAuth.getInstance().signOut(); //Then call signout method
     }
     else{
       TokenNo=1; //store token no in db
     }
   }
}

这里发生的事情:
当用户首次登录时,调用onNewToken时,它将进入其他位置,然后TokenNo从0更新为1。
当您禁用任何用户时,令牌将自动刷新。然后调用OnNewToken,然后TokenNo> = 1,因此用户将被注销。

注意::当用户首次登录时,即如果未存储TokenNo变量,则将其存储为0。

供参考:https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/FirebaseMessagingService

答案 3 :(得分:0)

尚未进行测试,因为负责设置Firestore规则的后端程序员今天已经不在了,但从理论上讲这应该可行:(这是我明天要测试的东西)

具有一个FirebaseAuth.AuthStateListener负责根据用户的状态提供用户界面

这结合了Firestore中的规则

match /collection
allow read: if isAuth();

isAuth在哪里:

function isAuth() {
  return request.auth.uid != null;
}

如果随后在登录时禁用了用户,则每当用户尝试从集合中读取数据时,都应拒绝该用户,并应进行signOut()调用。 然后,AuthStateListener将对其进行检测,然后将用户注销。

答案 4 :(得分:0)

我能想到的唯一方法是在开始活动中添加if-else块。 将用户的状态(已验证/禁止/删除)存储在Firebase实时数据库中。然后在应用程序启动时获取用户状态并添加代码:

if (currentUserStatus.equals("banned"))
{
currentUser.logout();
}

答案 5 :(得分:0)

我要做的是在为每个用户注册一个以UID作为文档ID的Firestore文档时创建的。在本文档中,我存储一个数组,该数组存储单个用户登录到新设备时收到的所有fcm令牌。这样,我将始终跟踪用户的登录位置。当用户手动注销时,fcm令牌将从Firestore中以及设备上的文档中删除。

为了能够在用户登录的任何地方注销该用户,我执行了以下操作。启动应用程序后,一旦用户登录,我就启动一个快照侦听器,该侦听器侦听用户文档中的所有更改。进行更改后,我将立即检索新的fcm令牌数组,在该数组内搜索本地当前设备的fcm令牌。如果找到,我什么也不做。如果fcm令牌不再存在于数组中,我将调用本地注销方法,然后返回登录屏幕。

以下是我在iOS上快速使用的方法。闭包(passOnMethod)只会触发对登录视图控制器的放松选择。

import Foundation
import Firebase

class FB_Auth_Methods {

let db = Firestore.firestore()
var listener: ListenerRegistration?

func trackLoginStatus(passOnMethod: @escaping () -> () ) {
    listener?.remove()
    if let loggedInUserA_UID = Auth.auth().currentUser?.uid {
        listener = db.collection(K.FStore.collectionOf_RegisteredUsers_Name)
            .document(loggedInUserA_UID)
            .addSnapshotListener { (snapshotDocument, error) in
                if let error = error {
                    print(error)
                } else {
                    if let document = snapshotDocument {
                        if let data = document.data() {
                            if let fcmTokens = data[K.FStore.Users.fcmTokens] as? [String] {
                                print("Found the following tokens: \(fcmTokens)")
                                self.compareTokensAgainstCurrentDeviceToken(fcmTokens: fcmTokens, passOnMethod: { () in
                                    passOnMethod()
                                })
                            }
                        }
                    }
                }
        }
    }
}

func compareTokensAgainstCurrentDeviceToken(fcmTokens: [String], passOnMethod: @escaping () -> () ) {
    InstanceID.instanceID().instanceID { (result, error) in
        if let error = error {
            print(error)
        } else if let result = result {
            if fcmTokens.contains(result.token) {
                print("Token found, doing nothing")
            } else {
                print("Token no longer found, logout user")
                do {
                    try Auth.auth().signOut()
                    InstanceID.instanceID().deleteID { error in
                        if let error = error {
                            print(error)
                        } else {
                            passOnMethod()
                        }


                    }
                    } catch let signOutError as NSError {
                        print (signOutError)
                    }
                }
            }
        }
    }
}

这是我在当前设备上各处注销用户时使用的方法。

func deleteAllFcmTokensExceptCurrent(loggedInUserA: User, passOnMethod: @escaping () -> () )  {

    InstanceID.instanceID().instanceID { (result, error) in
        if let error = error {
            print(error)
        } else if let result = result {
            let batch = self.db.batch()

            let deleteAllFcmRef = self.db.collection(K.FStore.collectionOf_RegisteredUsers_Name).document(loggedInUserA.uid)
            batch.updateData([K.FStore.Users.fcmTokens: FieldValue.delete()], forDocument: deleteAllFcmRef)

            let updateFcmTokenRef = self.db.collection(K.FStore.collectionOf_RegisteredUsers_Name).document(loggedInUserA.uid)
            batch.updateData([K.FStore.Users.fcmTokens: FieldValue.arrayUnion([result.token])], forDocument: updateFcmTokenRef)

            batch.commit { (error) in
                if let error = error {
                    print(error)
                } else {
                    passOnMethod()
                }
            }
        }
    }
}