当用户使计算机进入睡眠状态时,将其从网站注销


11

这是一个奇怪的问题。我们有一个Laravel网站,在所说的网站上,每个用户都有一个计时器,在启动之前,他们会在15分钟内处于非活动状态。

我们通过一个React组件中位于页面上的计时器来执行此操作,它可以按期望的方式工作,但是现在我们遇到了一个新问题:如果用户登录并关闭笔记本电脑的盖子,则网站应该启动它们。银行这样做,学校和大学这样做,政府场所也这样做。因此有可能,只是不确定如何。

我们使用laravel-websockets库和Echo 来使用Web套接字。我希望看到的是:

  • 关闭笔记本电脑启动后,您将进入登录屏幕。因此,下次打开笔记本电脑并登录时,会在登录屏幕上看到浏览器。它并不需要很快发生,但是我们需要一种方法来将一些内容发送到前端,基本上告诉他们刷新页面,一旦会话被终止,我们将会话生存时间设置为15分钟。

有人在其他类似问题中提出了建议:

最受欢迎的一种似乎是使用网络套接字,侦听用户断开连接然后再启动它们,这很好,而且一切正常,但是如何将请求发送到已暂停然后再启动的浏览器?

我发现了requestIdleCallback()但是,如果我已经在该站点上安装了心跳计时器,那么我不希望这就是我想要的。它也不适用于所有浏览器。

我对如何完成此操作非常迷失,我可以举的例子是:

登录到您的银行,使计算机进入睡眠状态,等待15-20分钟,唤醒计算机,然后登录,然后在登录屏幕上看到您的银行已将您带入。那就是我想要的。但是我不知道该怎么做到。

您不能从后端将事件发送到“正在休眠”的浏览器,虽然是的,这必须是后端解决方案,但是如何更新前端,以便重新唤醒笔记本电脑时它们出现在注销屏幕上还是电脑?


7
只需将会话库克过期日期设置为“现在+ 15分钟” ...尽管您仍然可以看到最后一个屏幕,但是如果cookie过期,则无法在该会话中采取行动。和“启动到登录界面” -我敢肯定,有一个操作系统的设置,会自动注销闲置一段时间后,电脑..
拉斯Stegelitz

1
每当网站加载时,您都可以初始化一个Javascript计时器,其超时与会话cookie相同...如果计时器“响起”,则用户长时间处于不活动状态。然后,您将其注销(AJAX呼叫),然后将浏览器重定向到登录屏幕或“对不起,由于您
Lars Stegelitz

1
好的,我已经完成了,现在添加答案。
拿督DT

1
这有用吗?
拿督DT

1
@DatoDT不,一个我使用laravel,两个我已经使用了我在开篇中表达的laravel套接字,两个您的代码非常混乱,不是OOP,未经测试,我永远也不会使用它。我本质上是在寻找Laravel解决方案。
TheWebs

Answers:


0

更新

对于WebSocket的要求,我假设你使用Laravel的WebSocketspusherPusher.io 不支持超时,您可以阅读此支持文章“您打算向Channels pusher-js客户端库添加连接超时功能吗?” 。如果启用Laravel调试模式(APP_DEBUG=true 在内部 .env)并laravel-websockets从终端(php artisan websockets:serve)开始,则可以对其进行测试,以便查看输出日志事件。如果您尝试合上笔记本电脑盖或将计算机设置为休眠模式(sleep),则不会看到有关此事件的任何消息。您不能使用pusher协议来做到这一点。有在场事件member_removed ,但这仅在您关闭标签页或注销时触发。当然,您可以将您的客户端自定义事件触发到状态通道,但是要做到这一点,您还需要在客户端设置计时器,并且您必须为laravel-websockets服务器创建服务提供者,例如github问题“存在一种方法实施webhooks?”

有人在其他类似问题中提出了建议:

...

  • 要在前端运行计时器(我们这样做,当您合上笔记本电脑盖时它会停止

发生这种情况是因为客户端计时器在休眠状态下暂停了执行,因此它们从以前的位置继续执行。但是,如果您使用日期变量来节省时间,则当计算机进入休眠状态时该变量将不会更新,因此,通过检查与当前时间相比具有显着意义的日期变量您将知道该变量何时从睡眠状态中退出差异,并且将大于计时器间隔。

在客户端中实现时间逻辑

您还可以在相关的Q / A中看到此实现任何台式机浏览器都可以检测到计算机何时从睡眠状态恢复吗?

您可以在客户端中设置一个计时器,使其每分钟运行一次。 我们将不依赖计时器间隔,而是如果自上一个计时器以来的时间间隔大于分钟,则计时器将检查外部作用域日期变量15。如果是,则意味着浏览器/ JS由于某种原因(可能是设备的休眠状态(sleep))暂停了执行,然后将用户重定向到注销路径。

JS客户端代码示例:

// Set a variable to check previous time
let clientSession = new Date;

// Setup the client session checking timer
let clientSessionTimer = setInterval(() => {
  const now = new Date;
  // Get how many seconds have passed since last check
  const secondsSpan = (now - clientSession) / 1000;

  // If the 1 minute timer has exceeded 15 minutes trigger logout and clear timer
  if (secondsSpan > (60 * 15)) {
    // For some reason JS halted execution, so we'll proceed with logging out
    clearInterval(clientSessionTimer);
    window.location.href = '/logout/session'
  } else {
    // The timer runs as it should, update the clientSession time
    clientSession = now;
  }

}, 1000 * 60);

您可以在此处查看此简单示例,但要使用1秒计时器15注销的第二个计时器。最好先在笔记本电脑上进行测试,方法是合上盖子,然后在15秒钟后再将其打开两分钟,因为如果正在运行许多程序,则计算机需要一些时间来保存内存状态,以便完成休眠模式并暂停执行。

网络工作者示例

您甚至可以使用Web Workers API来设置Web Worker,以使其更加安全:

页面JS代码:

const logoutWorker = new Worker('logoutWorker.js');
logoutWorker.onmessage = function (ev) {

  if (ev && ev.data === 'wakeup') {
    logoutWorker.terminate();
    // window.location.href = '/logout/session'
  } else {
    // The timer runs as it should, nothing to do
  }
}

网络工作者 logoutWorker.js代码:

let clientSession = new Date();

let clientSessionTimer = setInterval(() => {
  const now = new Date;
  const secondsSpan = (now - clientSession) / 1000;

  if (secondsSpan > 15) {
    postMessage('wakeup'); // Send a message wakeup to the worker page
    clearInterval(clientSessionTimer); // Clear the timer
  } else {
    clientSession = now; // Update the clientSession timer variable
    postMessage('update'); // And post a message to the page ONLY IF needed
  }
}, 1000);

您还可以在此处使用相同的15秒计时器检查Web Worker示例。


无论您做什么,这都会在15秒后注销您,不确定是否是他要的东西。
Islam Elshobokshy

@IslamElshobokshy你说得对,谢谢。我忘了更新clientSession变量。您可以再次检查我的答案,我什至还添加了一个Web Worker示例。
Christos Lytras

请更新仍无法使用的示例示例。无论如何,第一个都会在15秒后将您注销。第二个永远不会使您注销。
伊斯兰堡Elshobokshy

@IslamElshobokshy我当然已经更新了。在出现问题之前,现在可以按预期运行。如果没有,请重新整理页面,或者?v=1在最后添加类似的参数。
Christos Lytras

1
伟大的解决方案+ 3
AmerllicA

0

首先,让我们详细解释为何银行网站在15分钟无活动后将您注销。这是安全性的PCI要求。

PCI-DSS要求8.1.8

8.1.8如果会话闲置超过15分钟,则要求用户重新进行身份验证以重新激活终端或会话。

为了实现这一目标,解决方案实际上比您想象的要原始得多要。它既不需要使用websocket,也不需要了解客户端计算机的状态(睡眠或清醒或其他方式)。所需要做的就是知道当前使用该会话的请求和最后一次使用相同会话的请求之间的时间,并确保它们之间的间隔不超过15分钟。如果它们是用户,则将被重新认证。如果不是,则可以继续请求。

“会话超时”消息

然后,您可能想知道(如果这么简单)将计算机置于睡眠状态并唤醒后,会话超时消息如何出现。这部分看似简单。

当计算机进入睡眠状态时,浏览器实际上会断开所有TCP / IP连接,从而关闭javascript引擎中的事件循环。因此计时器不起作用。但是,当浏览器再次唤醒时,它将尝试刷新某些内容,包括页面本身。因此,刷新页面后,请求将返回到服务器,并调用服务器以要求用户重新进行身份验证。

但是,这不能解释某些银行网站所采用的javascript消息模式(如果您要指的是这种模式)。同样,在所有情况下,并非所有浏览器都会在页面上进行硬刷新。因此可以采用另一种方法。而不是让浏览器中的计时器在15分钟后超时,您可以简单地将页面加载时间存储在javascript中作为时间戳,并具有1秒钟的时间间隔来将该时间戳与计算机的当前时间戳进行比较。如果相隔15分钟以上,则应终止会话。

window.onload = function() {

    sessionStart = Date.now();
    timer = setInterval(function() {
        if (Date.now() - sessionStart > 15 * 60 * 1000) {
            clearTimeout(timer);
            alert("Session Timed out!");
            window.location = "http://www.example.com/login";
        }
    }, 1000);


};

即使计算机进入睡眠状态并且计时器停止运行,会话最终也会在服务器端超时(有关详细信息,请参见下面的部分),当计算机再次唤醒时,间隔为1秒的计时器最终将再次启动,并调用消息(好像用户在计算机睡眠时超时)。在计算机进入睡眠状态和唤醒计算机之间所花费的时间无关紧要,因为时间戳会保留在内存中。客户端与服务器之间的断开连接并不重要,因为它们不需要为了在服务器端正确终止会话而传达此信息。服务器可以执行自己的垃圾回收并终止会话,而无需来自客户端的通信(即,异步地)。

信不信由你,银行不关心客户内部的活动。他们只关心服务器的请求活动。因此,如果您想知道当用户在同一页面上停留了这么长时间时,他们如何使会话保持活动状态超过15分钟,他们只是在询问用户是否仍然在后台发送AJAX请求以刷新会话想要继续。

这可以在onload我们之前使用的同一事件回调中完成,如下所示:

window.onload = function() {

    sessionStart = Date.now();
    timer = setInterval(function() {
        if (Date.now() - sessionStart > 10 * 60 * 1000) {
           if (confirm("Your session is about to timeout. Do you wish to continue?")) {
                // send ajax request to refresh session TTL here
                // reset the timer
                sessionStart = Date.now();
            }
        } else if (Date.now() - sessionStart > 15 * 60 * 1000) {
            clearTimeout(timer);
            alert("Session Timed out!");
            window.location = "http://www.example.com/login";
        }
    }, 1000);


};

在服务器端处理会话终止

为了在服务器端处理会话终止,有几种方法。根据您使用的是哪种,您将需要不同的策略。一种是使用PHP的默认会话处理程序,并将设置为session.max_lifetime15分钟后过期(这将完全删除服务器端的会话数据,从而使客户端的cookie无效)。

如果使用默认的会话处理程序机制,则可能会遇到问题,具体取决于使用的是哪个处理程序(文件,memcached,redis,自定义等)。

使用文件(默认处理程序),垃圾收集以两种方式之一发生:

  • 大多数基于Debian的系统都通过cron作业来执行自己的GC(这对您的情况非常有用)
  • 其他发行版让PHP的默认GC机制对其进行处理,该机制基于对PHP的每个传入请求的概率结果,该结果检查会话文件上的文件mtime并将其删除session.max_lifetime。这种方法的问题在于,在通信量较低的站点上,会话可能会在服务器上长时间停留在那里,直到有足够的请求(取决于session.gc_probability分数)来调用GC来清理会话文件。

使用基于Memcached和Redis的处理程序,您就不会遇到这个问题。他们将自动清除内存。会话可能仍会在其生命周期内保留一段时间,但是守护程序将无法访问它们。如果您担心此安全性问题,则可以加密静态会话,或者找到具有更严格的内存清除GC机制的键/值存储。

使用自定义会话处理程序,您将必须构建自己的GC机制。通过SessionHandlerInterface实现gc将会话的最大生存期间隔交给您的方法,您将负责根据该间隔验证会话是否已超过生存期,并从那里进行垃圾回收。

您还可以设置一个单独的端点,该端点检查会话TTL(通过客户端的异步AJAX请求),如果会话已过期,则发送回响应(强制javascript重新验证用户)。


0

因此,Idea位于setInterval和Sockets的后面,大多数浏览器都支持setInterval,几乎每个浏览器都支持javascript WbsocketApi。

简要概述:setInterval()-当您的计算机处于睡眠/暂停/休眠模式时,将暂停此函数行为;在唤醒模式时,它将恢复自身的状态。

以下代码首先执行以下操作(也许同时),但它启动php server_socket来监听连接,

比javascript websocket api每2秒发送一次当前时间戳(以Unix时间戳毫秒为单位),您可以将1秒钟取决于您。

在该php服务器套接字获取此时间后,检查是否有与上次比较的时间,第一次实例化代码时php没有与上一次的时间比较的内容与从javascript websocket发送的时间进行比较,因此php什么都不做,只是将这段时间保存在名为“ prev_time”的会话中,并等待从JavaScript套接字接收另一个时间数据,因此这里开始第二个周期。当php服务器从javascript WebsocketApi中获取新的时间数据时,它会检查它是否有与上次时间类似的东西来与这个新接收的时间数据进行比较,这意味着php会检查是否存在名为“ prev_time”的会话,因为我们在第二个周期中php发现它存在,抓住它的价值,然后做$diff = $new_time - $prev_time,$ diff为2秒或2000毫秒,因为请记住我们的setInterval周期每2秒发生一次,而我们发送的时间格式以毫秒为单位,

比PHP检查if($diff<3000)差异是否小于3000,如果它知道用户处于活动状态,那么您也可以根据需要操作此秒,我选择3000,因为网络中可能存在的延迟几乎是不可能的,但是您知道我总是谨慎它涉及网络,因此让我们继续,当php确定用户处于活动状态时,php只是重置“ prev_time”会话,其值$new_time是新接收的,并且仅出于测试目的,它将消息发送回javascript套接字,

但是如果$diff大于3000,则表示某件事使我们的setInterval暂停了,并且只能发生,我想您已经知道我在说什么,因此按照elseif($diff<3000))的逻辑,您可以通过销毁特定会话来注销用户,如果要重定向,您可以将一些文本发送到javacript套接字并创建一个将window.location = "/login"根据文本执行的逻辑,这就是代码:

首先,它是index.html文件,仅用于加载javascript:

<html>
    <body>
        <div id="printer"></div>
        <script src="javascript_client_socket.js"></script>
    </body>
</html>

那么它是javascript代码,编码不是很漂亮,但是您可以弄清楚它们的重要性:

var socket = new WebSocket('ws://localhost:34237'); // connecting to socket
    // Open the socket
socket.onopen = function(event) { // detecting when connection is established
        setInterval(function(){ //seting interval for 2 seconds
            var date = new Date(); //grabing current date
            var nowtime = Date.parse(date); // parisng it in miliseconds
            var msg = 'I am the client.'; //jsut testing message


            // Send an initial message
            socket.send(nowtime); //sending the time to php socket
    },2000);

};


// Listen for messages
socket.onmessage = function(event) { //print text which will be sent by php socket 
    console.log('php: ' + event.data);
};

// Listen for socket closes
socket.onclose = function(event) {
    console.log('Client notified socket has closed', event);
};

现在这里是php代码的一部分,不要担心也有完整的代码,但这部分实际上就是上述工作,您也会遇到其他功能,但是它们是用于解码和使用javascript套接字的,所以这是正确的事情在这里阅读评论,它们很重要:

<?php 
            $decoded_data = unmask($data /* $data is actual data received from javascript socket */); //grabbing data and unmasking it | unmasking is for javascript sockets don't mind this
            print("< ".$decoded_data."\n");
            $response = strrev($decoded_data);
            $jsTime = (int) $decoded_data; /* time sent by javascript in MILISECONDS IN UNIX FORMAT  */
            if (isset($_SESSION['prev_time'])) { /** check if we have stored previous time in the session */
               $prev_time = (int) $_SESSION['prev_time']; /** grabbing the previous time from session */
               $diff = $jsTime-$prev_time; /** getting the difference newly sent time and previous time by subtracting */
               print("$jsTime - $prev_time = $diff"); /** printing the difference */
               if($diff<3000){ /** checking if difference is less than 3 second if it is it means pc was not at sleep
                               *** you can manipulate and have for example 1 second = 1000ms */
                    socket_write($client,encode("You are active! your pc is awakend"));
                    $_SESSION['prev_time'] = $jsTime; /** saving newly sent time as previous time for future testing whcih will happen in two seconds in our case*/
                }else { /** if it is more than 3 seconds it means that javascript setInterval function was paused and resumed after 3 seconds 
                            ** So it means that it was at sleep because when your PC is at sleep/suspended/hibernate mode setINterval gets pauesd */
                    socket_write($client,encode("You are not active! your pc is at sleep"));
                    $_SESSION['prev_time'] = $jsTime;
                }
            }else { /** if we have not saved the previous time in session save it  */
                $_SESSION['prev_time'] = $jsTime;
            }

            print_r($_SESSION);

?>

这是php的完整代码:

<?php
//Code by: Nabi KAZ <www.nabi.ir>
session_abort();
// set some variables
$host = "127.0.0.1";
$port = 34237;
date_default_timezone_set("UTC");


// don't timeout!
set_time_limit(0);

// create socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0)or die("Could not create socket\n");

// bind socket to port
$result = socket_bind($socket, $host, $port)or die("Could not bind to socket\n");

// start listening for connections
$result = socket_listen($socket, 20)or die("Could not set up socket listener\n");

$flag_handshake = false;
$client = null;
do {
    if (!$client) {
        // accept incoming connections
        // client another socket to handle communication
        $client = socket_accept($socket)or die("Could not accept incoming connection\n");
    }

    $bytes =  @socket_recv($client, $data, 2048, 0);
    if ($flag_handshake == false) {
        if ((int)$bytes == 0)
            continue;
        //print("Handshaking headers from client: ".$data."\n");
        if (handshake($client, $data, $socket)) {
            $flag_handshake = true;
        }
    }
    elseif($flag_handshake == true) {

        /*
        **** Main section for detectin sleep or not **
        */
        if ($data != "") {
            $decoded_data = unmask($data /* $data is actual data received from javascript socket */); //grabbing data and unmasking it | unmasking is for javascript sockets don't mind this
            print("< ".$decoded_data."\n");
            $response = strrev($decoded_data);
            $jsTime = (int) $decoded_data; /* time sent by javascript in MILISECONDS IN UNIX FORMAT  */
            if (isset($_SESSION['prev_time'])) { /** check if we have stored previous time in the session */
               $prev_time = (int) $_SESSION['prev_time']; /** grabbing the previous time from session */
               $diff = $jsTime-$prev_time; /** getting the difference newly sent time and previous time by subtracting */
               print("$jsTime - $prev_time = $diff"); /** printing the difference */
               if($diff<3000){ /** checking if difference is less than 3 second if it is it means pc was not at sleep
                               *** you can manipulate and have for example 1 second = 1000ms */
                    socket_write($client,encode("You are active! your pc is awakend"));
                    $_SESSION['prev_time'] = $jsTime; /** saving newly sent time as previous time for future testing whcih will happen in two seconds in our case*/
                }else { /** if it is more than 3 seconds it means that javascript setInterval function was paused and resumed after 3 seconds 
                            ** So it means that it was at sleep because when your PC is at sleep/suspended/hibernate mode setINterval gets pauesd */
                    socket_write($client,encode("You are not active! your pc is at sleep"));
                    $_SESSION['prev_time'] = $jsTime;
                }
            }else { /** if we have not saved the previous time in session save it  */
                $_SESSION['prev_time'] = $jsTime;
            }

            print_r($_SESSION);

           /*
        **** end of Main section for detectin sleep or not **
        */ 


        }
    }
} while (true);

// close sockets
socket_close($client);
socket_close($socket);
$client = null;
$flag_handshake = false;

function handshake($client, $headers, $socket) {

    if (preg_match("/Sec-WebSocket-Version: (.*)\r\n/", $headers, $match))
        $version = $match[1];
    else {
        print("The client doesn't support WebSocket");
        return false;
    }

    if ($version == 13) {
        // Extract header variables
        if (preg_match("/GET (.*) HTTP/", $headers, $match))
            $root = $match[1];
        if (preg_match("/Host: (.*)\r\n/", $headers, $match))
            $host = $match[1];
        if (preg_match("/Origin: (.*)\r\n/", $headers, $match))
            $origin = $match[1];
        if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $headers, $match))
            $key = $match[1];

        $acceptKey = $key.'258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
        $acceptKey = base64_encode(sha1($acceptKey, true));

        $upgrade = "HTTP/1.1 101 Switching Protocols\r\n".
            "Upgrade: websocket\r\n".
            "Connection: Upgrade\r\n".
            "Sec-WebSocket-Accept: $acceptKey".
            "\r\n\r\n";

        socket_write($client, $upgrade);
        return true;
    } else {
        print("WebSocket version 13 required (the client supports version {$version})");
        return false;
    }
}

function unmask($payload) {
    $length = ord($payload[1]) & 127;

    if ($length == 126) {
        $masks = substr($payload, 4, 4);
        $data = substr($payload, 8);
    }
    elseif($length == 127) {
        $masks = substr($payload, 10, 4);
        $data = substr($payload, 14);
    }
    else {
        $masks = substr($payload, 2, 4);
        $data = substr($payload, 6);
    }

    $text = '';
    for ($i = 0; $i < strlen($data); ++$i) {
        $text .= $data[$i] ^ $masks[$i % 4];
    }
    return $text;
}

function encode($text) {
    // 0x1 text frame (FIN + opcode)
    $b1 = 0x80 | (0x1 & 0x0f);
    $length = strlen($text);

    if ($length <= 125)
        $header = pack('CC', $b1, $length);
    elseif($length > 125 && $length < 65536)$header = pack('CCS', $b1, 126, $length);
    elseif($length >= 65536)
    $header = pack('CCN', $b1, 127, $length);

    return $header.$text;
}

注意: $new_time变量$jsTime在代码中

创建文件夹,然后将其复制并粘贴到文件中,然后使用以下命令运行php socket:php -f server_socket.php进入本地主机并对其进行测试,打开控制台以查看消息,该消息将显示“您处于活动状态”或“您处于非活动状态” (当您从睡眠中回来时);您的可执行文件将在用户进入睡眠状态而不是在睡眠状态时发生,因为此时所有内容都缓存在pagefile(windows)或swap(linux)中


创建文件夹,然后将其复制并粘贴到文件中,然后使用以下命令运行php socket:php -f server_socket.php进入本地主机并对其进行测试,打开控制台以查看消息,该消息将显示“您处于活动状态”或“您处于非活动状态” (当您从睡眠中回来时);您的可执行文件将在用户进入睡眠状态而不是在睡眠状态时发生,因为此时所有内容都缓存在pagefile(windows)或swap(linux)中
Dato DT

0

我想我有个主意,您已经讨论了很多有关银行登录/注销系统如何工作的方法。

情况1:如果用户处于活动状态,则可以无限时间访问该网页

每当用户登录时,在您的后端启动一个计时器(设置所需的时间限制),例如15分钟。现在是什么意思?这意味着,如果用户未在网页上执行任何活动,则我们会将其注销。

现在,您可以从头开始将用户活动发送到后端(可以使用套接字或长时间轮询发送),这基本上将重置计时器,并且用户可以在任意时间主动使用该网页。

如果用户将PC置于睡眠状态,计时器将不会重置,并且一旦计时器结束,您可以使会话无效。

如果要在用户电脑进入睡眠状态后立即使其失效,则可以设置会话验证时间的限制。例如,当用户登录时,我们将创建仅在10秒内有效的会话,一旦收到用户活动请求,我们就可以重置计时器并提供新的会话密钥。

我希望这可以帮助你。如果您有任何问题,请告诉我。


-1

我写了一个脚本来检测机器是否进入睡眠状态。想法是,当机器处于睡眠状态时,所有脚本都会停止。因此,如果我们在timeInterval内跟踪当前时间。每当timeInterval触发当前时间减(-)时,新时间应足够接近timeInterval。因此,如果我们要检查计时器是否闲置了X个时间,可以检查时间差是否大于X。

实例打击检查计算机是否已进入睡眠状态超过15秒。请注意,当您使计算机进入睡眠状态时,大约需要再花15秒钟才能了解所有处理器。(在我的PC上测试时)。

(function() {
    this.SleepTimer = function() {
        // console.log('sleep timer initiated');
        // Create global element references
        this.sleepTimer = null;
        this.maxTime = null;
        this.curDate = null;
        this.newDate = null;
        this.timer = null;
        this.timeInterval = 1000;

        this.sleepTimer = new CustomEvent("sleepTimer", {
		    "detail": {
		    	"maxTime":this.maxTime,
				"idelFor": this.newDate - this.curDate,
				"timer": this.timer
			}
		});

        // Define option defaults
        var defaults = {
            maxTime: 10000,
            timeInterval: 1000,
            autoStart: true,
            console: false,
            onStart: null,
            onIdel: null
        }
        // Create options by extending defaults with the passed in arugments
        if (arguments[0] && typeof arguments[0] === "object") {
            this.options = extendDefaults(defaults, arguments[0]);
        }
        if (this.options.timeInterval) {
            this.timeInterval = Math.max(1000, this.options.timeInterval);
            this.maxTime = Math.max(this.options.maxTime, 10000);
        } else {
        	this.options = defaults;
        }

        if(this.options.autoStart === true) this.start()
        // Utility method to extend defaults with user options
        
    }
    function extendDefaults(source, properties) {
        var property;
        for (property in properties) {
            if (properties.hasOwnProperty(property)) {
                source[property] = properties[property];
            }
        }
        return source;
    }
    SleepTimer.prototype.start = function(){
        var _ = this;
    	this.options.onStart()
        this.curDate = Date.now();

        this.timer = setInterval(function() {
            _.newDate = Date.now();
            var diff = _.newDate - _.curDate;

            // for debugging
            if(_.options.console && diff > _.timeInterval){
            	console.log('Your PC was idel for ' + diff / 1000 + 's of ' + _.maxTime /1000 + 's. TimeInterval is set to ' + _.timeInterval / 1000 + 's');
            }
            
            if (diff < _.maxTime) {
                _.curDate = _.newDate;
            } else {
            	_.options.onIdel();
                // alert('You have been idle for ' + diff / 1000 + 's');
                clearTimeout(_.timer);
            }
        }, this.timeInterval); // seconds
    }
}());

var sleepTimer = new SleepTimer({
	maxTime: 15000,
	console: true,
	onStart: function(){
		console.log('sleepTimer started.');
	},
	onIdel: function(){
		alert('Your session expired! Please login again.');
	}
});


请说明为什么这种情况行不通,如果您不这样做
Lasithds

-1

我已经使用AWS Cognito,Lambda Authorizers和Redis实现了完全相同的要求,目前我无法共享代码,但是我可以告诉您如何使用这些组件实现所有内容,相同的概念可以与其他组件一起使用非AWS组件。

首先,要实现非活动注销,您将必须在服务器端进行此操作,就好像有人只是关闭计算机一样,前端网站也不会注销它们。我使用了ACTIVE用户的概念。当用户成功通过身份验证时,我在TTL中以15分钟的TTL存储一个键值为username&的条目ACTIVE(如果要允许给定用户同时进行多个会话,则可以为username + sessionid)。

在我的自定义授权者中,当用户为ACTIVE&时,他们具有有效的令牌,我授予他们对受保护资源的访问权限,最重要的是,我在另一个Redis中添加了usernameACTIVE

每当用户注销时,我都会在身份管理解决方案(Cognito)中将其注销,并将其标记为INACTIVE。请注意,如果用户在15分钟内未点击API,则他们将不再可以使用ACTIVE其用户名输入,并且将无法再访问API并必须再次登录,为此,他们将被重定向。

这种方法要考虑很多事情,因为一件事情通常授权者会缓存结果一定时间,例如,如果您以5分钟的速度缓存结果,那么您的用户可能会在10分钟后以用户身份注销可能会访问缓存,而不是不会刷新ACTIVE条目的授权者。

同样重要的是,如果给定用户ACTIVE具有高可用性,并且要确保在发生故障时能够快速恢复,请确保使用什么来存储。

以这种方式使用缓存存储的方法类似于如何将令牌失效改型为无状态授权协议(例如OAuth2)。

我们已经使用这种方法已有几个月了,它似乎对我们来说很好用,可能需要处理一些令人讨厌的事情,我曾在AWS世界中期望过可以使用盒解决方案,但是没有什么可说的。


我们还幸存渗透测试(;这就是我们的要求从最初的来了,我们的应用程序是一个金融服务为主的产品,我们必须实现这个作为一项要求。
Snickers3192
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.