1

论证和研究

我有一个需要用户登录才能查看的网站。当用户登录时,我想关注他们的用户会话。我的意思是我想知道他们的用户会话是否已过期,因此重定向他们。

每个用户的会话持续 1 小时(或我设置的任何时间),如果他们访问不同的页面(如大多数登录系统),则会重置。

目前,我有以下算法:

  1. 用户到达私有页面(调用的javascript方法isUserAuthorized()被执行)
  2. javascript 方法向页面“ajax.example.net/authorized ”isUserAuthorized()发出 AJAX 请求
  3. 此页面返回一个 JSON 对象,指示用户的当前状态,如下所示:

{ authorized: true, timeout: 3600000 }

  1. 然后 javascript 方法设置超时以在timeout毫秒内再次调用该方法,假设会话将在那时结束。
  2. timeout如果会话已结束,则重定向用户,否则以毫秒为单位调用方法。

我不喜欢这种当前方法有两个原因:

  1. 我在客户端和服务器时钟之间的时间同步方面遇到了问题,这很奇怪,但它肯定会导致问题......
  2. 它在网页的背景中留下了一个超时,并且由于这个站点的 javascript 很重,我宁愿没有这个额外的超时,以保持站点尽可能流畅。

我的问题

因此,我的问题是,有人能想出更好的方法来实现这一目标吗?我曾考虑过长轮询或 websockets,但我不是 100% 确定如何使用其中任何一个,而且我发现的 websockets 教程不是很好!这些实际上会是更好的解决方案吗?

我可以解决时间同步问题,但在此之前,我想确保没有更好的方法来实现这一点......

如果有帮助,这是我当前的代码:

// Set the Authorized Timeout
MN.authorizedTimeout = setTimeout(function(){MN.isUserAuthorized});

/**
 * Is User Authorized
 * Checks to see if the current user is authorized and
 * makes sure their session is still active
 */
MN.isUserAuthorized = isUserAuthorized;
function isUserAuthorized(){
    // TEMPORARY
    console.log('authorising');
    // Set the authorized var
    var authorized = false;
    // Clear the current timeout
    clearTimeout(MN.authorizedTimeout);
    // Send request to determine whether the user is authorized
    $.ajax({
        url: "//ajax.example.net/authorized",
        type: "GET",
        dataType: "JSON",
        cache: false,
        async: false,
        success: function(data){
            console.log(data);
            if(data.authorized){
                // If the user is authorized then check again in timeout milliseconds
                MN.authorizedTimeout = setTimeout(MN.isUserAuthorized,data.timeout_milliseconds);
                // Set authorized to true
                authorized = true;
            }else{
                // If the session has expired then proceed to informing the user
                MN.userSessionExpired();
                // Set authorized to false
                authorized = false;
            }
        }
    });
    // Return the session status boolean
    return authorized;
}
4

2 回答 2

1

从总体上讲,您希望服务器上有一些东西可以在用户会话到期时提醒前端。

长轮询可以做到这一点。基本上,您将拥有一个后端控制器,它接受连接并保留它们,直到它收到发送响应的信号或连接超时。所以你的前端会有一个循环,基本上发送一个请求并等待响应。如果响应返回为空,则表示超时,因此发送一个新请求。如果响应有内容,则不是超时,因此您可以采取行动。这实现了您的目标,并且许多此类系统都是以这种方式构建的。但是,反向使用 HTTP 是一种 hack,并且不会生成干净的代码。

websocket 是客户端和服务器之间的双向接口。这是您的客户端 js 的样子。

  function connect(){
    websocket = new WebSocket("wss://yoursite.com:8080");
    //attach event handlers
    websocket.onmessage = onMessage;
  }
  function onMessage(evt){
    // do your thing
  }

一旦你打电话connect(),你可以放心,onMessage()当服务器需要到达客户端时,它会照顾你。对我来说,从服务器向客户端发送消息正是我们拥有 websocket 的原因,因此它们是完成这项工作的正确工具。

于 2013-05-20T23:00:14.297 回答
1

更新答案:

尽管如此,我认为计算在线状态服务器端是一种更好的做法。所以你可以确保没有与时间不一致。你只有你的服务器时间。

为了获得在线状态,您可以采用长轮询方法。我给你举了一个例子:

(function checkLoginStatus(){
    $.ajax({ 
      type: 'POST',
      url: 'loginstatus.php',
      data: {userid : 25},
      success: function(data){
        if(data.logged_in !== true){
          //Log the user out
        }
      }, 
      dataType: "json", 
      complete: checkLoginStatus, 
      timeout: 15000 
    });
})();

这将确保仅在经过 15 秒且请求完成时才发出新请求。

老答案:

如果您唯一关心的是监视登录用户,则无需轮询。我会保留整个服务器端。只需在您的用户表中添加一个“last_active”字段。

每当用户交互(访问另一个站点)时,将时间戳更新为当前时间戳。

要检测用户是否在线,请获取当前时间戳并从中减去“last_active”时间戳。如果差异大于一小时,您就知道您的用户处于非活动状态。

这就是我通常的处理方式。它也比使用 AJAX 更有效(关于资源)。

于 2013-05-13T17:11:55.110 回答