如何从应用程序远程强制注销firebase auth用户

Posted

技术标签:

【中文标题】如何从应用程序远程强制注销firebase auth用户【英文标题】:How to force logout firebase auth user from app remotely 【发布时间】:2019-04-04 21:17:52 【问题描述】:

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

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

我等了 2 天多,仍然注意到用户已登录并且可以访问 firestore 数据。

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

谁能指出我做错了什么?

【问题讨论】:

【参考方案1】:

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

访问令牌一旦生成,就无法撤销。这意味着即使您禁用该用户的帐户,他们也可以继续访问长达一个小时。

如果这太长,诀窍(正如我对您链接的问题的回答中所提到的)是在您的数据库(或其他地方)中维护一个被阻止用户的列表,然后在您的安全规则中检查该列表(或其他授权层)。

例如在实时数据库中,您可以创建一个被屏蔽用户的 UID 列表:

banned_uids: 
  "uid1": true
  "uid2": true

然后在您的安全规则中检查:

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

【讨论】:

谢谢,@frank-van-puffelen。在我们的案例中,我们尝试禁用用户并尝试撤销他/她的刷新令牌,但即使等待 1 小时后用户仍然能够访问数据(我们也等待了 2 天 :))。我们还在 Firestore 中添加了规则,只允许经过身份验证的用户。如果我的理解有误,请帮助我理解何时撤销用户刷新令牌? 我注意到我说的是 ID 令牌,我的意思是访问令牌,所以我解决了这个问题。撤销访问令牌是不够的,这就是安全规则的用武之地。如果这些步骤对您不起作用,请准确显示您所做的事情。没有代码或精确的重现步骤,任何人都很难说出你在哪里犯了错误。 @FrankvanPuffelen 在 Firebase 身份验证控制台中禁用用户后,用户需要多长时间才能注销?有这方面的文档吗? "如果您禁用该用户的帐户,他们最多可以继续访问一个小时" 这是一个愚蠢的问题,但是您实际上是如何在 Firebase 规则 DSL 中定义banned_uuids 的?只是复制粘贴是行不通的?【参考方案2】:

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

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

    将 FCM 令牌保存在 firebase Realtime 的集合中。 在服务中配置 Android 客户端应用程序。 LINK你必须在收到带有特殊字符串的消息时强制退出。 在云功能中做你需要的触发器,当你需要用户退出时发送数据LINK。

成功!

【讨论】:

我们如何使用 nodejs sdk 来实现这一点,我也没有使用 firebase db 只需保存令牌并使用api发送数据firebase.google.com/docs/cloud-messaging/… 不知道Android App在后台运行的情况下是否有效?【参考方案3】:

根据您的情况,我假设您需要在用户被禁用时让用户注销。 使用一个全局变量来存储 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 然后它进入 else 然后 TokenNo 从 0 更新为 1。 当您禁用任何用户时,会自动刷新令牌。然后调用 OnNewToken 然后 TokenNo>=1 ,因此用户将被注销。 注意: 当用户第一次登录时,即如果没有存储 TokenNo 变量,则将其存储为 0。 供参考:https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/FirebaseMessagingService

【讨论】:

据我所知,以上onNewToken属于FCM。您能否解释一下为什么我们在刷新 FCM 令牌时将用户注销?【参考方案4】:

尚未测试,因为我们负责设置 Firestore 规则的后端程序员已经离开了一天,但理论上这应该可以工作:(明天我会测试)

有一个 FirebaseAuth.AuthStateListener 负责根据用户的状态为 UI 提供服务

这与firestore中的规则相结合

match /collection
allow read: if isAuth();

isAuth 在哪里:

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

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

【讨论】:

【参考方案5】:

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

if (currentUserStatus.equals("banned"))

currentUser.logout();

【讨论】:

【参考方案6】:

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

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

这是我在 ios 上 swift 中使用的方法。闭包(passOnMethod)只会触发登录视图控制器的展开segue。

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()
                
            
        
    

【讨论】:

以上是关于如何从应用程序远程强制注销firebase auth用户的主要内容,如果未能解决你的问题,请参考以下文章

远程和以编程方式注销活动域用户

如何在 Firebase 3.0 中注销用户?

当我在firebase上删除他的帐户时如何从应用程序中注销用户?

在 iOS 应用中使用远程配置 Firebase

使用Firebase Google用户身份验证更改用户

从 Firebase 中的 SafetyNet 注销应用程序检查中的应用程序