Firebase注销用户所有会话

11

我在我的iOS应用中使用Firebase身份验证。在Firebase中,当用户使用Firebase登录我的应用程序,然后注销时,有没有办法注销所有其他设备的用户会话?我可以使用Firebase管理员SDK实现吗?


你需要为移动应用程序自己完成这个任务。在Firebase数据库中的User节点中获取一个令牌,并在每次登录应用程序时重新生成它,如果在appDidBecomeActiveappDidFinishLaunching方法中匹配此令牌与已登录用户的令牌不同,则手动注销该用户并将其带到身份验证屏幕。 - TheTiger
这只是一个想法,但这会是一个良好的用户体验吗?我使用我的iOS设备,这样我就可以无缝地从一个设备切换到另一个设备——在我的iMac上聊天,然后拿起手机继续对话(Handoff)。 - Jay
@Jay 我认为注销所有会话的用户对于安全改进是有好处的。 - Karen Hovhannisyan
1
@Jay 这取决于应用程序的类别。如果这是与安全有关的东西,比如银行、钱包或个人数据应用程序,那么保持单个用户登录就很好。 - TheTiger
@TheTiger 我完全同意,这就是我问的原因。用户如何处理与应用程序的用例直接相关。我认为在问题中提供更多信息可能会导致答案,但是现在它有点模糊,不清楚“注销”是什么意思。换句话说,Firebase可以在节点上设置观察者,通知应用程序将用户从Firebase中注销,但这是否也意味着将用户从应用程序本身注销?还是他们仍然可以访问他们正在查看的数据,而没有新数据。 - Jay
3个回答

13

当我遇到此问题时,我通过云函数解决了它。点击此链接查看更多详细信息。

按照以下步骤进行操作:

  1. 如不存在,请使用Firebase Cloud Functions设置Web服务器。
  2. 使用Admin SDK(这是唯一可行的方法)- [访问此链接] (https://firebase.google.com/docs/admin/setup#initialize_the_sdk).
  3. 创建一个API,接收UID并根据上述第一个链接中指定的方式撤销当前会话。
  admin.auth().revokeRefreshTokens(uid)
    .then(() => {
      return admin.auth().getUser(uid);
    })
    .then((userRecord) => {
      return new Date(userRecord.tokensValidAfterTime).getTime() / 1000;
    })
    .then((timestamp) => {
      //return valid response to ios app to continue the user's login process
  });

Voila用户已注销。希望这能帮助解决问题。


1
这样做会“注销”当前会话吗? - James Chen
是的,@JamesChen,它将注销所有活动会话。 - hazelcodes
2
我该如何在当前设备上保留用户登录状态并注销所有其他设备? - lazzy_ms

3

Firebase不提供此功能,您需要自己进行管理。

这里是Firebase文档,他们没有提到任何与单个用户登录相关的内容。

以下是您可以尝试的方法:

Firebase数据库中的用户节点(保存用户其他数据的地方)中取一个令牌,并在每次登录应用程序时重新生成它,在appDidBecomeActiveappDidFinishLaunching或可能在每次执行任何与Firebase有关的操作或某个固定时间间隔内将此令牌与已经登录的用户的令牌(本地保存)进行匹配。如果令牌不同,则手动注销用户并将其带到身份验证屏幕。


2
我所做的是:
在Firestore中创建了一个集合,名为“activeSessions”。用户电子邮件作为对象的ID,并使用“activeID”字段保存最近的会话ID。
在登录页面代码中:
每次用户登录时生成一个用户会话ID。 将此ID添加到本地存储(应在添加之前清除)。 将当前用户电子邮件替换为生成的ID,以在集合“activeSessions”中替换“activeID”。
function addToActiveSession() {
  var sesID = gen();

  var db = firebase.firestore();
  localStorage.setItem('userID', sesID);
  db.collection("activeSessions").doc(firebase.auth().currentUser.email).set({
    activeID: sesID
  }).catch(function (error) {
      console.error("Error writing document: ", error);
    });

}
function gen() {
  var buf = new Uint8Array(1);
  window.crypto.getRandomValues(buf);
  return buf[0];
}
function signin(){
 firebase.auth().signInWithEmailAndPassword(email, password).then(function (user) {
      
      localStorage.clear();
      addToActiveSession();
      }
    }), function (error) {
      // Handle Errors here.
      var errorCode = error.code;
      var errorMessage = error.message;
      if (errorCode === 'auth/wrong-password') {
        alert('wrong pass');
      } else {
        alert(errorMessage);
      }
      console.log(error);
    };
}

然后我在每个页面上检查本地存储中的ID会话是否与Firestore中的“activeID”相同,如果不同则注销。

function checkSession(){
  
  var db = firebase.firestore();
  var docRef = db.collection("activeSessions").doc(firebase.auth().currentUser.email);
        docRef.get().then(function (doc) {
          alert(doc.data().activeID);
          alert(localStorage.getItem('userID'));
          if (doc.data().activeID != localStorage.getItem('userID')) {
            alert("bie bie");
            firebase.auth().signOut().then(() => {
        
              window.location.href = "signin.html";
         }).catch((error) => {
           // An error happened.
         });
            window.location.href = "accountone.html";
          } else{alert("vse ok");}
        }).catch(function (error) {
          console.log("Error getting document:", error);
        });
}

提示:为了注销不活动的会话,需要刷新窗口。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接