Выход пользователя из веб-сайта, когда он переводит компьютер в спящий режим

11

Это странно. У нас есть веб-сайт Laravel, и на указанном сайте у нас есть таймер на пользователя, где они получают 15 минут неактивности перед загрузкой.

Мы делаем это через таймер, который находится на странице в реагирующем компоненте, он работает так, как мы хотим, но теперь у нас есть новая проблема: если пользователь вошел в систему и закрыл крышку своего ноутбука, веб-сайт должен загрузить их , Это делают банки, школы и университеты, правительственные сайты тоже. Так что возможно, просто не уверен как.

Мы используем веб-сокеты, используя библиотеку laravel-websockets и Echo. Я хотел бы, чтобы это произошло:

  • Как только вы закроете свой ноутбук, загрузитесь к экрану входа. Поэтому в следующий раз, когда вы откроете ноутбук и войдете в систему, вы увидите браузер на экране входа в систему. Это не должно происходить так быстро, но нам нужен способ отправить что-то внешнему интерфейсу, в основном, сказать им, чтобы они обновляли страницу, когда сеанс завершается, мы устанавливаем время жизни сеанса на уровне 15 минут.

Некоторые люди предложили в других подобных вопросах:

  • создать собственный обработчик веб-сокета
  • Чтобы сравнить cookie-файл сеанса (в браузере) с cookie-файлом пользователя на серверной части.
  • Чтобы таймер работал на передней панели (у нас он останавливается, когда вы закрываете крышку ноутбука)

Наиболее популярным кажется использование веб-сокетов, прислушиваясь к тому, что пользователь отключается, а затем загружает их, и это нормально, но как же тогда вы отправляете запрос в браузер, который приостановлен, чтобы затем загрузить их?

Я нашел requestIdleCallback () Но, опять же, я не думаю, что это то, что я хочу, если у меня уже есть таймер сердцебиения на сайте. Это также не работает во всех браузерах.

Я очень запутался здесь, как это сделать, пример, который я могу привести:

Войдите в свой банк, переведите компьютер в спящий режим, подождите 15-20 минут, разбудите компьютер, войдите в систему и увидите, что ваш банк теперь отображает вас на экране входа в систему. Вот чего я хочу . Но я не знаю, как этого добиться.

Вы не можете отправлять события в «спящий» браузер с бэкэнда, и хотя да, это должно быть бэкэнд-решение, как вы тогда обновите интерфейс, чтобы они были на экране выхода из системы, когда они пробуждают ноутбук? или компьютер?

TheWebs
источник
7
Просто установите дату окончания сеанса cooke на «сейчас + 15 минут» ... хотя вы все равно можете видеть последний экран, вы не сможете действовать в этом сеансе, если срок действия cookie истек. И «загрузочный экран входа в систему» ​​- я почти уверен, что есть настройка ОС, которая автоматически отключает компьютер после определенного времени бездействия ..
Ларс Стегелиц,
1
Вы можете запускать таймер Javascript всякий раз, когда сайт загружается, с тем же временем ожидания, что и ваш сеансовый файл cookie ... если таймер «звонит», пользователь неактивен так долго. Затем вы выйдете из него (вызов AJAX) и перенаправите браузер на экран входа в систему или на экран «извините, мы вышли из-за отсутствия активности»;)
Ларс Стегелиц,
1
Хорошо, я сделал это, я добавляю ответ прямо сейчас.
Дато DT
1
так было ли это полезно?
Дато DT
1
@DatoDT Нет, один я использую laravel, два я уже использую сокеты laravel, как указано в моем первом посте, два ваш код очень грязный, не ООП, не проверен, и я бы никогда не использовал его. По сути, я ищу решение Laravel.
TheWebs

Ответы:

0

ОБНОВИТЬ

Что касается запроса WebSocket, я предполагаю, что вы используете Laravel WebSockets с pusher. Pusher.io не поддерживает тайм-аут , вы можете прочитать эту статью поддержки "Планируете ли вы добавить функцию тайм-аута соединения в клиентскую библиотеку Channels pusher-js?" , Вы можете проверить это, если включите режим отладки Laravel ( APP_DEBUG=true внутри .env ) и начнете laravel-websocketsс терминала ( php artisan websockets:serve), чтобы вы могли видеть события выходного журнала. Если вы пытаетесь закрыть ноутбук крышку или набор компьютер в режим гибернации ( спящий ), вы не увидите никаких сообщений относительно этого события. Вы не можете сделать это с pusherпротоколом. Есть событие Присутствияmember_removed , но срабатывает только при закрытии вкладки или выходе из системы. Конечно , вы можете запустить ваш клиент пользовательского события в канал присутствия, но для этого необходимо также установка таймера на сторону клиента , и вы должны будете создать поставщик услуг для laravel-websocketsсервера , как этот GitHub вопрос «существует путь к реализовать вебхуки? ,

Некоторые люди предложили в других подобных вопросах:

...

  • Чтобы таймер работал на передней панели ( у нас он останавливается, когда вы закрываете крышку ноутбука )

Это происходит потому, что таймеры клиента останавливают выполнение в спящем режиме, поэтому они продолжают с того места, где были раньше. Но если вы используете переменную даты для экономии времени , эта переменная не будет обновляться, когда компьютер перейдет в спящий режим, поэтому вы узнаете, когда он выйдет из спящего режима, проверив эту переменную даты, которая по сравнению с текущим временем будет иметь значительное значение. Разница и будет больше, чем интервал таймера.

Реализация временной логики в клиенте

Вы также можете увидеть эту реализацию для этой связанной Q / A : могут ли какие-либо браузеры настольных компьютеров определять, когда компьютер выходит из спящего режима?

Вы можете настроить таймер в клиенте для запуска каждую минуту. Мы не будем полагаться на интервал таймера , но вместо этого этот таймер проверит внешнюю переменную области видимости, если промежуток времени с последнего таймера больше 15минут; если это так, то это означает, что браузер / JS по какой-то причине остановил выполнение , возможно, спящий режим устройства ( спящий режим ), а затем вы перенаправили пользователя на маршрут выхода из системы.

Пример кода клиента 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 секунд каждую минуту, потому что если у вас много запущенных программ, компьютеру требуется некоторое время, чтобы сохранить состояние памяти, чтобы завершить режим гибернации и остановить выполнение.

Пример веб-работников

Вы даже можете использовать API Web Workers, чтобы настроить веб-работника как можно более безопасно:

Код 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);

Вы также можете проверить пример Web Worker с тем же 15таймером секунд здесь .

Христос Литрас
источник
Это выводит вас из системы через 15 секунд, независимо от того, что вы, не уверен, что это то, что он ищет.
Ислам Эльшобокший
@IslamElshobokshy Вы правы, спасибо за улов. Я забыл обновить clientSessionпеременную. Вы можете проверить мой ответ снова, я даже добавил пример Web Worker.
Христос Литрас
Пожалуйста, обновите примеры примеров, которые все еще не работают. Первый выходит из системы через 15 секунд, несмотря ни на что. Второй никогда не выходит из системы.
Ислам Эльшобокший
@IslamElshobokshy Я обновил его, конечно. Раньше у него была проблема, а теперь все работает как положено. Пожалуйста, обновите страницу, если у вас нет или, возможно, добавьте парам, как ?v=1в конце.
Христос Литрас
1
Отличное решение + 3
AmerllicA
0

Во-первых, давайте рассмотрим, почему веб-сайты Banking выходят из системы через 15 минут без активности. Это требование PCI для безопасности.

Требование PCI-DSS 8.1.8 :

8.1.8 Если сеанс простаивал более 15 минут, потребуйте от пользователя повторной аутентификации для повторной активации терминала или сеанса.

Чтобы достичь этого, решение на самом деле гораздо более примитивно, чем вы думаете . Он не требует использования веб-сокетов и не знает ничего о состоянии компьютера клиента (в спящем режиме, в режиме бодрствования или иным образом). Все, что требуется, это знать время между текущим запросом, использующим этот сеанс, и последним запросом, использующим тот же сеанс, и убедиться, что они не превышают 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_lifetimeсрок действия истекает через 15 минут (это полностью удаляет данные сеанса на стороне сервера, что делает недействительным куки-файл клиента).

Если вы позволите механизму обработчика сеанса по умолчанию сделать это, вы можете столкнуться с проблемами в зависимости от того, какой обработчик используется (файлы, memcached, redis, custom и т. Д.).

С файлами (обработчик по умолчанию) сборка мусора происходит одним из двух способов:

  • Большинство систем, основанных на Debian, выполняют свой собственный GC через работу cron (что отлично подходит для вашего сценария)
  • Другие дистрибутивы позволяют стандартному механизму GC PHP обрабатывать его, который основан на вероятностном результате каждого входящего запроса в 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 отправляет текущую метку времени в миллисекундах метки времени Unix каждые 2 секунды, вы можете иметь 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, и есть только один способ, которым это может произойти, и я думаю, что вы уже знаете, что я говорю, поэтому в elseлогике ( if($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 перейдите на локальный хост и протестируйте его, откройте консоль, чтобы увидеть сообщения, в которых будет указано «вы активны» или «вы не активны» (когда ты выходишь из сна); ваше выполнение будет происходить, когда пользователь выйдет из спящего режима, а не когда он спит, потому что в этот момент все кэшируется в файл подкачки (windows) или в swap (linux)

Dato DT
источник
создать папку и просто скопировать и вставить это в файлах запуск PHP сокета с помощью команды: PHP -f server_socket.php перейти на локальный хост и протестировать его откройте консоль , чтобы увидеть сообщения , которые он будет говорить «вы активны» или «вы не активны» (когда ты выходишь из сна); ваше выполнение будет происходить, когда пользователь выйдет из спящего режима, а не когда он спит, потому что в этот момент все кэшируется в файл подкачки (windows) или в swap (linux)
Dato DT
0

Я думаю, у меня есть идея, вы много обсуждали о том, как работает система входа / выхода из банка.

Случай 1: Доступ пользователя к веб-странице в течение неограниченного времени, если пользователь активен

Всякий раз, когда пользователь вошел в систему, запустите таймер на своем бэкэнде (установите ограничение по времени, сколько хотите), скажем, 15 минут. Теперь, что это значит? Это означает, что если пользователь не выполняет никаких действий на веб-странице, мы вышлим его / ее из системы.

Теперь спереди вы можете отправить пользовательскую активность на ваш бэкэнд (может быть отправлен с использованием сокета или длинного опроса), что в основном сбрасывает таймер, и пользователь может активно использовать веб-страницу в любое время по своему усмотрению.

Если пользователь переводит свой компьютер в спящий режим, таймер не будет сброшен, и вы можете отменить сеанс, как только таймер закончится.

Если вы хотите сделать недействительным пользовательский сеанс, как только он переведет компьютер в спящий режим, вы можете установить ограничение времени проверки сеанса. Например, когда пользователь входит в систему, мы создадим сеанс, который будет действителен только в течение 10 секунд, и как только мы получим запрос активности пользователя, мы можем сбросить таймер и предоставить новый ключ сеанса.

Я надеюсь, это поможет вам. Дайте мне знать, если у вас есть какие-либо вопросы.

Суровая Шривастава
источник
-1

Я написал сценарий, чтобы определить, ушел ли аппарат в спящий режим. Идея в том, что когда машина находится в спящем настроении, все сценарии будут остановлены. Поэтому, если мы будем отслеживать текущее время в течение timeInterval. Каждый раз, когда timeInterval запускает текущее время минус (-), новое время должно быть достаточно близко к timeInterval. Поэтому, если мы хотим проверить, не работал ли таймер в течение X времени, мы можем проверить, больше ли разница во времени, чем X.

Пример удара проверяет, был ли компьютер переведен в спящий режим более чем на 15 секунд. Обратите внимание, что, когда вы переводите компьютер в спящий режим, потребуется еще 15 секунд, чтобы представить все процессоры. (При тестировании на МОЕМ ПК).

(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
источник
Пожалуйста, объясните, почему это не сработает, если это не так в вашем случае
Lasithds
-1

Я выполнил точно такое же требование, используя AWS Cognito, с Lambda Authorizers & Redis, я не могу поделиться кодом на этом этапе, но я могу рассказать вам все, как он реализован с этими компонентами, те же концепции можно использовать с другими не AWS компоненты.

Во-первых, при реализации выхода из неактивности вам придется делать это на стороне сервера, как если бы кто-то просто выключил свой компьютер, интерфейсный веб-сайт не мог бы выйти из него. Я использовал концепцию ACTIVEпользователей. Когда пользователи успешно проходят аутентификацию, я сохраняю в Redis с TTL 15 минут запись с ключом их username& значением ACTIVE(это может быть имя пользователя + sessionid, если вы хотите разрешить несколько сеансов для данного пользователя одновременно).

В моих пользовательских Авторизаторах, когда у пользователя есть ACTIVE& у него есть действующий токен, я даю ему доступ к защищенному ресурсу И, что наиболее важно, я делаю еще один вклад в Redis с username& ACTIVE.

Всякий раз, когда пользователь выходит из системы, я выхожу из него в своем решении для управления идентификацией (Cognito) и помечаю их как INACTIVE. Обратите внимание, что если пользователь не нажмет на API в течение 15 минут, у него больше не будет записи ACTIVEпротив своего имени пользователя, и он больше не сможет получить доступ к API и должен будет снова войти в систему, для чего он будет перенаправлен.

При таком подходе нужно учитывать много вещей, во-первых, часто Авторизаторы кешируют результаты в течение некоторого времени, и если, к примеру, вы кешируете результат в течение 5 минут в качестве примера, то ваш пользователь может выйти из системы через 10 минут как ваш пользователь. может ударить кеш вместо Авторизатора, который не обновит ACTIVEзапись.

Также важно убедиться, что все, что вы используете для хранения, если данный пользователь ACTIVEявляется высокодоступным и быстро восстановится в случае сбоя.

Подход использования хранилища кэша таким способом аналогичен тому, как аннулирование токена модифицируется для протоколов авторизации без сохранения состояния, таких как OAuth2.

Мы использовали этот подход уже несколько месяцев, и, похоже, он нам подходит, это может быть немного раздражающим требованием, я ожидал, что в мире AWS будет готов к использованию. коробочного решения для этого, но не о чем было говорить.

Snickers3192
источник
Мы также прошли тест на ручку (это то, откуда изначально возникло наше требование, наше приложение является продуктом на основе финансовых услуг, и нам пришлось реализовать его как требование.
Snickers3192