Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/444.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何防止同一用户同时登录Firebase?_Javascript_Jquery_Web Applications_Firebase - Fatal编程技术网

Javascript 如何防止同一用户同时登录Firebase?

Javascript 如何防止同一用户同时登录Firebase?,javascript,jquery,web-applications,firebase,Javascript,Jquery,Web Applications,Firebase,我希望新的会话基本上“注销”以前的任何会话。例如,当您在一台计算机上进行身份验证会话时,在另一台计算机上启动新会话并在我们的应用程序上使用firebase进行身份验证将注销第一台计算机上的另一个会话 我还没有找到任何允许我“远程”注销会话的方法。我知道我可以在一个会话中取消对()和goOffline()的访问。但是如何从同一用户的不同身份验证会话中执行此操作 谢谢你的帮助 背景信息: 我使用简单的电子邮件/密码登录进行firebase身份验证 我还没有设置安全规则,尽管这正在进行中 我在Fire

我希望新的会话基本上“注销”以前的任何会话。例如,当您在一台计算机上进行身份验证会话时,在另一台计算机上启动新会话并在我们的应用程序上使用firebase进行身份验证将注销第一台计算机上的另一个会话

我还没有找到任何允许我“远程”注销会话的方法。我知道我可以在一个会话中取消对()和goOffline()的访问。但是如何从同一用户的不同身份验证会话中执行此操作

谢谢你的帮助

背景信息:

  • 我使用简单的电子邮件/密码登录进行firebase身份验证
  • 我还没有设置安全规则,尽管这正在进行中
  • 我在Firebase中使用Javascript

  • 一般的想法是,您希望在Firebase中创建一些元数据,它告诉您用户从多少个位置登录。然后,您可以使用此信息限制他们的访问

    要做到这一点,您需要生成自己的令牌(以便您的安全规则可以使用这些信息)

    1)生成令牌

    用于生成您自己的令牌。每个令牌应包含客户端的唯一ID(IP地址?UUID?)

    2)使用状态来存储用户的位置id

    有关详细信息,请查看底漆:

    var fb = new Firebase(URL);
    
    // after getting auth token back from your server
    var parts = deconstructJWT(token);
    var ref = fb.child('logged_in_users/'+token.id);
    
    // store the user's location id
    ref.set(token.location_id);
    
    // remove location id when user logs out
    ref.onDisconnect().remove();
    
    // Helper function to extract claims from a JWT. Does *not* verify the
    // validity of the token.
    // credits: https://github.com/firebase/angularFire/blob/e8c1d33f34ee5461c0bcd01fc316bcf0649deec6/angularfire.js
    function deconstructJWT(token) {
      var segments = token.split(".");
      if (!segments instanceof Array || segments.length !== 3) {
        throw new Error("Invalid JWT");
      }
      var claims = segments[1];
      if (window.atob) {
        return JSON.parse(decodeURIComponent(escape(window.atob(claims))));
      }
      return token;
    }
    
    3)添加安全规则

    在安全规则中,强制只有当前唯一位置可以读取数据

    {
      "some_restricted_path": {
         ".read": "root.child('logged_in_users/'+auth.id).val() === auth.location_id"
      }
    }
    
    4)控制登录用户的写访问权

    您需要设置一些系统来控制登录用户的写访问权限。显然,用户只能写入自己的记录。如果希望第一次登录尝试始终获胜,则使用
    “.write:”!data.exists()“

    但是,您可以通过允许最后一次登录获胜来大大简化,在这种情况下,它将覆盖旧的位置值,并且以前的登录将无效并无法读取

    5)这不是控制并发数的解决方案

    您不能使用此选项来阻止多个并发到您的Firebase。有关实现这一点的更多数据,请参见goOffline()和goOnline()(或获得付费计划,这样您就不会对连接设置硬限制)。

    TL;DR


    我们也遇到过这个话题。尽管这条线索已经过时,而且事实上它并没有完全勾勒出我们想要实现的完全相同的愿望,但是我们可以吸收一些关于“的答案”的一般概念。这些概念大致保持不变,但这条线索绝对值得一个更为最新的答案

    注意:在你马上阅读这个解释之前,要意识到这样一个事实:你可能会发现它有点脱离上下文,因为它没有完全涵盖原来的SO问题。事实上,组装一个系统以防止同时进行多个会话是一种完全不同的思维模式。更准确地说,是我们的思维模式适合我们的情景

    例如,当您在一台计算机上进行身份验证会话时,在另一台计算机上启动新会话并在我们的应用程序上使用firebase进行身份验证将注销第一台计算机上的另一个会话

    维护这种类型的“同时登录预防”意味着1)每个客户端的活动会话应该有所区别,即使它来自同一设备2)客户端应该从AFAICT Firebase无法使用的特定设备注销。FWIW您可以显式地使指定用户的所有刷新令牌过期,因此系统会提示您再次登录,但这样做的缺点是会破坏所有现有会话(即使是刚刚激活的会话)

    这些“间接费用”导致以稍微不同的方式处理问题。它的不同之处在于1)无需跟踪具体设备2)客户端以编程方式注销,而不会不必要地破坏其任何活动会话以增强用户体验


    利用这一点来完成跟踪客户端连接状态更改的繁重任务(即使连接因某种奇怪的原因而终止),但这里有一个问题:Firestore并不是本机提供的。请参阅以保持数据库同步。值得注意的是,与他们的示例相比,我们没有设置对特殊路径的引用。相反,我们利用观察者来响应身份验证状态的变化

    const getUserRef=userId=>firebase.database().ref(`/users/${userId}`);
    firebase.auth().onAuthStateChanged(用户=>{
    如果(用户){
    constuserref=getUserRef(user.uid);
    返回userRef
    .onDisconnect()文件
    .设置({
    你在线吗:错,
    最后一次看到:firebase.database.ServerValue.TIMESTAMP
    })
    .然后(()=>
    //一旦将`onDisconnect()`附加到用户的ref,这会将标志设置为true。
    userRef.set({
    你是在线的吗,
    最后一次看到:firebase.database.ServerValue.TIMESTAMP
    });
    );
    }
    });
    
    正确设置
    onDisconnect()
    后,如果用户尝试在另一个活动会话旁边启动登录,则必须确保该用户的会话,为此,将请求转发到数据库并对照相应的标志进行检查。因此,由于这种额外的往返过程,识别多个会话比通常要花费更多的时间,因此应该相应地调整UI

    const ensureUserSession=userId=>{
    const userRef=getUserRef(userId);
    返回userRef.one(“值”)。然后(快照=>{
    如果(!snapshot.exists()){
    //如果用户条目没有
    
    {
      "some_restricted_path": {
         ".read": "root.child('logged_in_users/'+auth.id).val() === auth.location_id"
      }
    }