当用户将计算机置于睡眠状态时,将用户从网站上注销

The*_*ebs 11 javascript php authentication laravel

这是一件很奇怪的事。我们有一个 Laravel 网站,在该网站上,我们为每个用户设置了一个计时器,他们在启动前有 15 分钟处于非活动状态。

我们通过一个位于 React 组件页面上的计时器来实现这一点,它按我们的意愿工作,但现在我们遇到了一个新问题:如果用户登录并关闭笔记本电脑的盖子,网站应该引导他们. 银行这样做,学校和大学这样做,政府网站也这样做。所以这是可能的,只是不确定如何。

我们确实使用 web sockets,使用laravel-websockets库和 Echo。我希望看到的是:

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

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

  • 创建自定义网络套接字处理程序
  • 将会话 cookie(在浏览器中)与后端的用户 cookie 进行比较。
  • 在前端运行计时器(我们这样做,当您关闭笔记本电脑盖时它就会停止)

最流行的似乎是使用网络套接字,监听用户断开连接然后启动它们,这很好,但是你如何向暂停的浏览器发送请求然后启动它们?

我找到了requestIdleCallback()但同样,如果我已经在网站上有一个心跳计时器,我认为这不是我想要的。它也不适用于所有浏览器。

我对如何做到这一点非常迷茫,我可以举的例子是:

登录您的银行,让您的计算机进入睡眠状态,等待 15-20 分钟,唤醒计算机,登录并看到您的银行现在在登录屏幕上显示您。这就是我想要的。但我不知道如何做到这一点。

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

Chr*_*ras 0

更新

关于 WebSocket 请求,我假设您正在使用Laravel WebSocketspusher. Pusher.io 不支持超时,您可以阅读这篇支持文章“您计划向 Channels Pusher-js 客户端库添加连接超时功能吗?” 。如果启用 Laravel 调试模式(APP_DEBUG=true 内部 .env)并laravel-websockets从终端(php artisan websockets:serve)开始,您可以对其进行测试,这样您就可以看到输出日志事件。如果您尝试关闭笔记本电脑盖或将计算机设置为休眠模式 ( sleep ),您将看不到有关此事件的任何消息。你不能用pusher协议来做到这一点。有Presence 事件,但仅当您关闭选项卡或注销时才会触发。当然,您可以将客户端自定义事件触发到存在通道,但要做到这一点,您还需要在客户端设置一个计时器,并且您必须为服务器创建一个服务提供者,就像这个 github 问题“Exist a way to实施网络钩子吗?” member_removed laravel-websockets

有些人在其他类似问题中建议:

...

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

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

在客户端实现时间逻辑

您还可以查看此相关 Q/A 的实现Can any Desktop browsers detector when the computer returns from sleep?

您可以在客户端中设置一个计时器每分钟运行一次。我们不会依赖计时器间隔,而是如果自上次计时器以来的时间跨度大于分钟,则计时器将检查外部范围日期变量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);
Run Code Online (Sandbox Code Playgroud)

您可以在此处检查这个简单的示例,但使用带有秒注销的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
  }
}
Run Code Online (Sandbox Code Playgroud)

网络工作者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);
Run Code Online (Sandbox Code Playgroud)

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