Melden Sie einen Benutzer von einer Website ab, wenn er seinen Computer in den Ruhezustand versetzt

11

Dies ist eine bizarre. Wir haben eine Laravel-Website und auf dieser Website haben wir einen Timer pro Benutzer, bei dem sie 15 Minuten lang inaktiv sind, bevor sie gebootet werden.

Wir tun dies über einen Timer, der sich in einer Reaktionskomponente auf der Seite befindet. Er funktioniert so, wie wir es möchten. Jetzt haben wir ein neues Problem: Wenn ein Benutzer angemeldet ist und den Deckel seines Laptops schließt, sollte die Website ihn starten . Banken tun dies, Schulen und Universitäten tun dies, Regierungsstellen tun dies auch. Es ist also möglich, nur nicht sicher wie.

Wir verwenden Web-Sockets, die Laravel-Websockets- Bibliothek und Echo. Was ich gerne sehen würde, ist:

  • Sobald Sie Ihren Laptop schließen, starten Sie den Anmeldebildschirm. Wenn Sie also das nächste Mal den Laptop öffnen und sich anmelden und den Browser sehen, befinden Sie sich auf dem Anmeldebildschirm. Es muss nicht so schnell gehen, aber wir brauchen eine Möglichkeit, etwas an das Front-End zu senden, das ihnen im Grunde sagt, dass sie die Seite aktualisieren sollen. Sobald die Sitzung beendet ist, setzen wir die Sitzungslebensdauer auf 15 Minuten.

Einige Leute haben in anderen ähnlichen Fragen vorgeschlagen:

Am beliebtesten scheint es zu sein, Web-Sockets zu verwenden und darauf zu warten, dass der Benutzer die Verbindung trennt und sie dann startet. Das ist in Ordnung, aber wie können Sie dann eine Anfrage an einen Browser senden, der angehalten ist, um sie dann zu starten?

Ich habe requestIdleCallback () gefunden Aber ich glaube auch nicht, dass dies das ist, was ich möchte, wenn ich bereits einen Heartbeat-Timer auf der Site habe. Es funktioniert auch nicht in allen Browsern.

Ich bin hier sehr verloren, wie ich das erreichen kann. Das Beispiel, das ich geben kann, ist:

Melden Sie sich bei Ihrer Bank an, schalten Sie Ihren Computer ein, warten Sie 15 bis 20 Minuten, wecken Sie den Computer, melden Sie sich an und sehen Sie, dass Ihre Bank Sie jetzt auf dem Anmeldebildschirm hat. Das will ich . Aber ich weiß nicht, wie ich das erreichen soll.

Sie können keine Ereignisse vom Back-End an einen "schlafenden" Browser senden, und obwohl dies eine Back-End-Lösung sein müsste, wie aktualisieren Sie das Front-End dann, damit sie beim erneuten Aufwecken des Laptops auf dem Abmeldebildschirm angezeigt werden oder Computer?

TheWebs
quelle
7
Setzen Sie einfach das Ablaufdatum für den Sitzungscooke auf "jetzt + 15 Minuten". Obwohl möglicherweise immer noch der letzte Bildschirm angezeigt wird, können Sie in dieser Sitzung nicht handeln, wenn das Cookie abgelaufen ist. Und der "Boot to Login-Bildschirm" - Ich bin mir ziemlich sicher, dass es eine Betriebssystemeinstellung gibt, die einen Computer nach einer bestimmten Zeit der Inaktivität automatisch abmeldet.
Lars Stegelitz
1
Sie können einen Javascript-Timer initiieren, wenn eine Site geladen wird, mit dem gleichen Zeitlimit wie Ihr Sitzungscookie. Wenn der Timer "klingelt", war der Benutzer so lange inaktiv. Sie würden ihn dann abmelden (AJAX-Anruf) und den Browser zum Anmeldebildschirm oder zum Bildschirm "Entschuldigung, wir haben Sie wegen Inaktivität abgemeldet" umleiten;)
Lars Stegelitz
1
Okay, ich habe es geschafft. Ich füge gerade die Antwort hinzu.
Dato DT
1
War das also nützlich?
Dato DT
1
@DatoDT Nein, eins Ich benutze Laravel, zwei Ich benutze bereits Laravel-Sockets, wie in meinem Eröffnungsbeitrag ausgedrückt, zwei Ihr Code ist sehr chaotisch, nicht OOP, nicht getestet und ich würde ihn niemals benutzen. Ich suche im Wesentlichen nach einer Laravel-Lösung.
TheWebs

Antworten:

0

AKTUALISIEREN

In Bezug auf die WebSocket-Anforderung gehe ich davon aus, dass Sie Laravel WebSockets mit verwenden pusher. Pusher.io unterstützt kein Timeout . Sie können diesen Support-Artikel lesen. "Planen Sie, der Client-Bibliothek pusher-js von Channels eine Funktion zum Timeout der Verbindung hinzuzufügen?" . Sie können es testen, wenn Sie den Laravel-Debug-Modus ( APP_DEBUG=true innen .env ) aktivieren und laravel-websocketsvom Terminal ( php artisan websockets:serve) aus starten, damit Sie die Ausgabeprotokollereignisse sehen können. Wenn Sie versuchen, den Laptopdeckel zu schließen oder den Computer in den Ruhezustand ( Ruhezustand ) zu versetzen , werden keine Meldungen zu diesem Ereignis angezeigt. Sie können es nicht mit dem pusherProtokoll tun . Es gibt das Präsenzereignismember_removed Dies wird jedoch nur ausgelöst, wenn Sie die Registerkarte schließen oder sich abmelden. Natürlich können Sie Ihr benutzerdefiniertes Client-Ereignis für den Anwesenheitskanal auslösen. laravel-websocketsDazu benötigen Sie jedoch auch ein Timer-Setup auf der Clientseite und müssen einen Dienstanbieter für den Server wie dieses Github-Problem erstellen "Exist a way to Webhooks implementieren? " .

Einige Leute haben in anderen ähnlichen Fragen vorgeschlagen:

...

  • Damit am vorderen Ende ein Timer läuft ( wir hören einfach auf, wenn Sie den Laptopdeckel schließen ).

Dies liegt daran, dass Client-Timer die Ausführung im Ruhezustand anhalten und somit an der Stelle fortfahren, an der sie zuvor waren. Wenn Sie jedoch eine Datumsvariable verwenden, um die Zeit zu sparen , wird diese Variable nicht aktualisiert, wenn der Computer in den Ruhezustand wechselt Sie wissen also, wann sie aus dem Ruhezustand wechselt, indem Sie diese Datumsvariable überprüfen, die im Vergleich zur aktuellen Uhrzeit von Bedeutung ist Differenz und ist größer als das Timer-Intervall.

Zeitlogik im Client implementieren

Sie können diese Implementierung auch in dieser zugehörigen Frage / Antwort sehen : Können Desktop-Browser erkennen, wann der Computer aus dem Ruhezustand wieder aufgenommen wird?

Sie können im Client einen Timer einrichten, der jede Minute ausgeführt wird. Wir werden uns nicht auf das Timer-Intervall verlassen , sondern dieser Timer überprüft eine Datumsvariable für den äußeren Bereich, wenn die Zeitspanne seit dem letzten Timer größer als 15Minuten ist. Wenn dies der Fall ist, bedeutet dies, dass der Browser / JS die Ausführung aus irgendeinem Grund angehalten hat , möglicherweise im Ruhezustand des Geräts ( Ruhezustand ), und Sie den Benutzer dann zur Abmelderoute umleiten.

Beispiel für einen JS-Clientcode:

// 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);

Sie können dieses einfache Beispiel überprüfen, aber hier einen 1zweiten Timer mit 15Sekunden-Abmeldung verwenden . Testen Sie es am besten auf einem Laptop, indem Sie den Deckel schließen und ihn nach 15 Sekunden wieder öffnen pro Minute Wenn viele Programme ausgeführt werden, benötigt der Computer einige Zeit, um den Speicherstatus zu speichern, um den Ruhezustand abzuschließen und die Ausführung anzuhalten.

Beispiel für Web-Worker

Sie können sogar die Web Worker-API verwenden, um einen Web Worker so einzurichten, dass er viel sicherer ist:

Seiten-JS-Code:

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
  }
}

Web-Worker- logoutWorker.jsCode:

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);

Sie können auch die Web Worker Beispiel mit der gleichen Check - 15Sekunden - Timer hier .

Christos Lytras
quelle
Dies meldet Sie nach 15 Sekunden ab, egal was passiert, nicht sicher, ob dies das ist, wonach er sucht.
Islam Elshobokshy
@IslamElshobokshy du hast recht, danke für den Fang. Ich habe vergessen, die clientSessionVariable zu aktualisieren . Sie können meine Antwort erneut überprüfen. Ich habe sogar ein Web Worker-Beispiel hinzugefügt.
Christos Lytras
Bitte aktualisieren Sie die Beispielbeispiele, die immer noch nicht funktionieren. Der erste meldet Sie nach 15 Sekunden ab, egal was passiert. Der zweite meldet Sie nie ab.
Islam Elshobokshy
@IslamElshobokshy Ich habe es natürlich aktualisiert. Früher hatte es ein Problem und jetzt funktioniert es wie erwartet. Bitte erneuern Sie die Seite, wenn Sie ?v=1am Ende noch keinen Parameter wie "Gefällt mir" hinzugefügt haben .
Christos Lytras
1
Tolle Lösung + 3
AmerllicA
0

Lassen Sie uns zunächst erläutern, warum sich Banking-Websites nach 15 Minuten ohne Aktivität abmelden. Dies ist eine PCI-Sicherheitsanforderung.

PCI-DSS-Anforderung 8.1.8 :

8.1.8 Wenn eine Sitzung länger als 15 Minuten inaktiv war, muss sich der Benutzer erneut authentifizieren, um das Terminal oder die Sitzung erneut zu aktivieren.

Um dies zu erreichen, ist die Lösung tatsächlich viel primitiver, als Sie es sich vorstellen . Es erfordert weder die Verwendung von Websockets noch das Wissen über den Zustand des Client-Computers (Schlaf oder Wach oder auf andere Weise). Sie müssen lediglich die Zeit zwischen der aktuellen Anforderung, die diese Sitzung verwendet, und der letzten Anforderung, die dieselbe Sitzung verwendet, kennen und sicherstellen, dass sie nicht länger als 15 Minuten voneinander entfernt sind. Wenn dies der Fall ist, muss der Benutzer erneut authentifiziert werden. Wenn dies nicht der Fall ist, können Sie mit der Anfrage fortfahren.

Die Meldung "Sitzungszeitüberschreitung"

Sie fragen sich dann wahrscheinlich (wenn es so einfach ist), wie die Meldung "Sitzungszeitüberschreitung" angezeigt wird, wenn Sie den Computer in den Ruhezustand versetzen und wieder aktivieren. Dieser Teil ist täuschend einfach.

Wenn der Computer in den Energiesparmodus versetzt wird, trennt der Browser tatsächlich alle TCP / IP-Verbindungen, wodurch die Ereignisschleife in der Javascript-Engine geschlossen wird. Timer funktionieren also nicht. Wenn der Browser jedoch wieder aufwacht, versucht er, einige Dinge zu aktualisieren, einschließlich der Seite selbst. Wenn die Seite aktualisiert wird, wird die Anforderung an den Server zurückgesendet, der den Server aufruft, damit der Benutzer sich erneut authentifizieren muss.

Dies berücksichtigt jedoch nicht das Modal der Javascript-Nachricht (wenn Sie sich darauf beziehen), das einige Bank-Websites tun. Außerdem führen nicht alle Browser in allen Szenarien eine harte Aktualisierung der Seite durch. Es kann also ein anderer Ansatz gewählt werden. Anstatt einen Timer im Browser zu haben, der nach 15 Minuten abläuft, können Sie die Ladezeit der Seite einfach in Javascript als Zeitstempel speichern und eine Zeitüberschreitung von 1 Sekunde festlegen, die diesen Zeitstempel mit dem aktuellen Zeitstempel des Computers vergleicht. Wenn sie mehr als 15 Minuten voneinander entfernt sind, sollte die Sitzung beendet werden.

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);


};

Selbst wenn der Computer in den Ruhezustand wechselt und der Timer stoppt, tritt auf der Serverseite möglicherweise eine Zeitüberschreitung auf ( Einzelheiten finden Sie im folgenden Abschnitt) ). Wenn der Computer wieder aufwacht, wird der Timer mit einem Intervall von 1 Sekunde schließlich erneut gestartet und ruft den auf Nachricht (als ob der Benutzer eine Zeitüberschreitung hatte, während der Computer schlief). Die Zeit, die zwischen dem Einschalten des Computers und dem Aufwachen des Computers verloren geht, spielt keine Rolle, da der Zeitstempel im Speicher verbleibt. Die Trennung zwischen Client und Server ist unwichtig, da diese Informationen nicht übermittelt werden müssen, damit die Sitzung auf der Serverseite ordnungsgemäß beendet wird. Der Server kann seine eigene Garbage Collection durchführen und die Sitzung ohne Kommunikation vom Client (dh asynchron ) beenden .

Ob Sie es glauben oder nicht, Banken kümmern sich nicht um Aktivitäten innerhalb des Kunden. Sie kümmern sich nur um die Anforderungsaktivität an den Server. Wenn Sie sich also fragen, wie sie die Sitzung länger als 15 Minuten am Leben erhalten, wenn sich der Benutzer so lange auf derselben Seite befindet, senden sie einfach im Hintergrund eine AJAX-Anfrage, um die Sitzung zu aktualisieren, nachdem sie den Benutzer gefragt haben, ob sie noch aktiv sind will weitermachen

Dies kann in demselben onloadEreignisrückruf erfolgen, den wir zuvor wie folgt verwendet haben:

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);


};

Behandlung der Sitzungsbeendigung auf der Serverseite

Um die Sitzungsbeendigung auf der Serverseite zu handhaben, gibt es verschiedene Ansätze. Je nachdem, welche Sie verwenden, benötigen Sie unterschiedliche Taktiken. Eine davon ist die Verwendung des Standard-Sitzungshandlers von PHP und das Festlegen dersession.max_lifetime Ablauf nach 15 Minuten abläuft (dadurch werden die Sitzungsdaten vollständig auf der Serverseite gelöscht, wodurch das Cookie des Clients ungültig wird).

Wenn Sie den Standardmechanismus für Sitzungshandler ausführen lassen, können Probleme auftreten, je nachdem, welcher Handler verwendet wird (Dateien, Memcached, Redis, Benutzerdefiniert usw.).

Bei den Dateien (Standardhandler) erfolgt die Speicherbereinigung auf zwei Arten:

  • Die meisten Debian-basierten Systeme führen ihre eigene GC über einen Cron-Job durch (was für Ihr Szenario hervorragend funktioniert).
  • In anderen Distributionen kann der Standard-GC-Mechanismus von PHP damit umgehen. Dies basiert auf einem probabilistischen Ergebnis jeder eingehenden Anforderung an PHP, bei dem die Datei-Mtime-Daten in Sitzungsdateien überprüft und die über die Datei hinaus gelöscht werden session.max_lifetime. Das Problem bei diesem Ansatz besteht darin, dass auf Websites mit geringem Datenverkehr eine Sitzung möglicherweise lange Zeit auf dem Server verbleibt, bis (abhängig von der session.gc_probabilityPunktzahl) genügend Anforderungen eingehen , um den GC zum Bereinigen der Sitzungsdateien aufzurufen.

Mit Memcached- und Redis-basierten Handlern haben Sie dieses Problem nicht. Sie werden den Speicher automatisch löschen. Sitzungen bleiben möglicherweise noch eine Zeit nach ihrem Leben im physischen Speicher, aber der Dämon kann nicht auf sie zugreifen. Wenn Sie sich aus Sicherheitsgründen Sorgen um dieses Bit machen, können Sie Ihre Sitzungen in Ruhe verschlüsseln oder einen Schlüssel- / Wertspeicher mit einem strengeren GC-Mechanismus zum Löschen des Speichers finden.

Mit einem benutzerdefinierten Sitzungshandler müssen Sie Ihren eigenen GC-Mechanismus erstellen. Durch würden SessionHandlerInterfaceSie eine gcMethode implementieren , die Ihnen das maximale Lebensdauerintervall der Sitzung übergibt, und Sie sind dafür verantwortlich, anhand dieses Intervalls zu überprüfen, ob die Sitzung ihre Lebensdauer überschritten hat, und von dort aus Ihre Garbage Collection durchzuführen.

Sie können auch einen separaten Endpunkt einrichten, der die Sitzungs-TTL überprüft (über eine asynchrone AJAX-Anforderung auf der Clientseite) und eine Antwort zurücksendet, wenn die Sitzung abgelaufen ist (wodurch das Javascript gezwungen wird, den Benutzer erneut zu authentifizieren).

Sherif
quelle
0

Idea steht also hinter setInterval und Sockets, setInterval wird in den meisten Browsern unterstützt und Javascript WbsocketApi wird in fast jedem Browser unterstützt.

Kurzübersicht: setInterval () - Dieses Funktionsverhalten folgt, wenn sich Ihr Computer im Ruhezustand / Suspend / Hibernate-Modus befindet, angehalten ist und wenn Sie sich im Wake-Modus befinden, setzt er sich fort.

Der folgende Code führt Folgendes aus: Zuerst (möglicherweise zur gleichen Zeit, aber) startet er php server_socket und lauscht den Verbindungen.

als javascript websocket api sendet aktuelle zeitstempel in unix zeitstempel millisekunden alle 2 sekunden können sie 1 sekunde haben es liegt an dir

nachdem dieser PHP-Server-Socket diese Zeit erhält und prüft, ob er etwas wie die vorherige Zeit zum Vergleichen hat, wenn der Code zum ersten Mal instanziiert wird, hat PHP nichts wie die vorherige Zeit, um ihn mit der Zeit zu vergleichen, die vom Javascript-Websocket gesendet wurde, also PHP tut nichts anderes, als diese Zeit in der Sitzung mit dem Namen 'prev_time' zu speichern und darauf zu warten, dass weitere Zeitdaten vom Javascript-Socket empfangen werden. Hier beginnt also der zweite Zyklus. Wenn der PHP-Server neue Zeitdaten von Javascript WebsocketApi einbindet, prüft er, ob er mit den neu empfangenen Zeitdaten vergleichbar ist. Dies bedeutet, dass der PHP prüft, ob eine Sitzung mit dem Namen 'prev_time' vorhanden ist, wie wir es im zweiten Zyklus feststellen es existiert, ergreift seinen Wert und folgt$diff = $new_time - $prev_time, $ diff beträgt 2 Sekunden oder 2000 Millisekunden, da unser setInterval-Zyklus alle 2 Sekunden stattfindet und das von uns gesendete Zeitformat in Millisekunden angegeben wird.

Als PHP prüft, if($diff<3000)ob der Unterschied weniger als 3000 beträgt, wenn bekannt ist, dass der Benutzer aktiv ist. Sie können diese Sekunden wieder nach Belieben bearbeiten. Ich wähle 3000, da eine mögliche Latenz im Netzwerk fast unmöglich ist, aber Sie wissen, dass ich immer vorsichtig bin, wenn Wenn es um Netzwerke geht, fahren wir fort. Wenn PHP feststellt, dass der Benutzer aktiv ist, setzt PHP nur die Sitzung 'prev_time' zurück, deren Wert $new_timeneu empfangen wurde, und sendet zu Testzwecken eine Nachricht an den Javascript-Socket zurück.

aber wenn $diffes mehr als 3000 ist, bedeutet dies, dass etwas unser setInterval angehalten hat und es nur möglich ist, und ich denke, Sie wissen bereits, was ich sage. In der elseLogik von ( if($diff<3000)) können Sie Benutzer abmelden, indem Sie eine bestimmte Sitzung zerstören, und wenn Sie Wenn Sie umleiten möchten, können Sie Text an den Javacript-Socket senden und eine Logik erstellen, die window.location = "/login"je nach Text ausgeführt wird. Hier ist der Code:

Zuerst ist es die Datei index.html, nur um Javascript zu laden:

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

dann ist es Javascript, es ist nicht wirklich schön codiert, aber Sie können herausfinden, LESEN SIE KOMMENTARE SIE SIND WICHTIG:

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);
};

Jetzt ist hier ein Teil des PHP-Codes, keine Sorge, es gibt auch vollständigen Code, aber dieser Teil ist tatsächlich das, was die oben genannten Jobs erledigt. Sie werden auch andere Funktionen erfüllen, aber sie dienen zum Dekodieren und Arbeiten mit Javascript-Sockets, so dass es tatsächlich richtig ist hier LESEN SIE KOMMENTARE SIE SIND WICHTIG:

<?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);

?>

Und hier ist der vollständige Code von 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;
}

HINWEIS LESEN SIE ES: Die $new_timeVariable befindet sich $jsTimeim Code

Erstellen Sie einen Ordner und kopieren Sie diesen und fügen Sie ihn in Dateien ein. Führen Sie den PHP-Socket mit dem folgenden Befehl aus: php -f server_socket.php Gehen Sie zum lokalen Host und testen Sie die geöffnete Konsole, um die Meldungen "Sie sind aktiv" oder "Sie sind nicht aktiv" anzuzeigen. (wenn du aus dem Schlaf kommst); Ihre Ausführung erfolgt, wenn der Benutzer aus dem Ruhezustand kommt, nicht wenn er sich im Ruhezustand befindet, da in diesem Moment alles in der Auslagerungsdatei (Windows) oder im Swap (Linux) zwischengespeichert wird.

Dato DT
quelle
Ordner erstellen und einfach kopieren und fügen Sie diesen in Dateien php Buchse mit dem Befehl ausführen: php -f gehen server_socket.php zum localhost und testen Sie es offen Konsolnachrichten zu sehen , es sagen „Sie sind aktiv“ oder „Sie sind nicht aktiv“ (wenn du aus dem Schlaf kommst); Ihre Ausführung erfolgt, wenn der Benutzer aus dem Ruhezustand kommt, nicht wenn er sich im Ruhezustand befindet, da in diesem Moment alles in der Auslagerungsdatei (Windows) oder im Swap (Linux) zwischengespeichert wird
Dato DT
0

Ich glaube, ich habe eine Idee, Sie haben viel darüber diskutiert, wie das Bank-Login / Logout-System funktioniert.

Fall 1: Unbegrenzter Zugriff der Webseite auf den Benutzer, wenn der Benutzer aktiv ist

Wenn sich ein Benutzer angemeldet hat, starten Sie einen Timer in Ihrem Backend (stellen Sie das gewünschte Zeitlimit ein), sagen wir 15 Minuten. Was bedeutet es nun? Wenn der Benutzer keine Aktivität auf der Webseite ausführt, werden wir ihn abmelden.

Jetzt können Sie die Benutzeraktivität von vorne an Ihr Backend senden (kann über Socket oder lange Abfrage gesendet werden), wodurch der Timer im Grunde zurückgesetzt wird und der Benutzer die Webseite für jede gewünschte Zeit aktiv nutzen kann.

Wenn der Benutzer seinen PC in den Energiesparmodus versetzt, wird der Timer nicht zurückgesetzt und Sie können die Sitzung nach Ablauf des Timers ungültig machen.

Wenn Sie die Benutzersitzung ungültig machen möchten, sobald sie ihren PC in den Ruhezustand versetzt, können Sie das Limit für die Überprüfungszeit der Sitzung festlegen. Wenn sich ein Benutzer anmeldet, erstellen wir beispielsweise die Sitzung, die nur 10 Sekunden lang gültig ist. Sobald wir die Benutzeraktivitätsanforderung erhalten, können wir den Timer zurücksetzen und einen neuen Sitzungsschlüssel bereitstellen.

Ich hoffe das hilft dir. Lassen Sie mich wissen, wenn Sie Fragen haben.

Harte Srivastava
quelle
-1

Ich habe ein Skript geschrieben, um festzustellen, ob die Maschine in den Ruhezustand versetzt wurde. Die Idee ist, dass alle Skripte angehalten werden, wenn die Maschine in Schlafstimmung ist. Daher, wenn wir die aktuelle Zeit innerhalb eines Zeitintervalls verfolgen. Jedes Mal, wenn timeInterval die aktuelle Zeit minus (-) auslöst, sollte die neue Zeit nahe genug an timeInterval liegen. Wenn wir daher überprüfen möchten, ob der Timer für die X-Zeit inaktiv war, können wir prüfen, ob der Zeitunterschied mehr als X beträgt.

Beispiel Blow prüft, ob der Computer länger als 15 Sekunden in den Ruhezustand versetzt wurde. Bitte beachten Sie, dass Sie beim Einschalten des Computers weitere 15 Sekunden benötigen, um alle Prozessoren zu entwickeln. (Beim Testen auf MEINEM 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
quelle
Bitte erklären Sie, warum dies nicht funktionieren würde, wenn dies in Ihrem Fall nicht der Fall ist
Lasithds
-1

Ich habe genau die gleiche Anforderung mit AWS Cognito implementiert, mit Lambda Authorizers & Redis. Ich kann den Code derzeit nicht freigeben, aber ich kann Ihnen alles darüber erzählen, wie er mit diesen Komponenten implementiert wird. Dieselben Konzepte können mit anderen verwendet werden Nicht-AWS-Komponenten.

Wenn Sie ein Inaktivitäts-Logout implementieren, müssen Sie es zunächst serverseitig ausführen. Wenn jemand seinen Computer einfach ausschaltet, werden sie von der Front-End-Website nicht abgemeldet. Ich habe das Konzept der ACTIVEBenutzer verwendet. Wenn Benutzer sich erfolgreich authentifizieren, speichere ich mit einer TTL von 15 Minuten in Redis einen Eintrag mit einem Schlüssel von username& einem Wert von ACTIVE(es kann Benutzername + Sitzungs-ID sein, wenn Sie mehrere Sitzungen für einen bestimmten Benutzer gleichzeitig zulassen möchten).

Wenn ein Benutzer in meinen benutzerdefinierten Autorisierern ACTIVEein gültiges Token hat, erteile ich ihm Zugriff auf die geschützte Ressource UND vor allem mache ich ein weiteres Put in Redis mit dem username& ACTIVE.

Immer wenn sich der Benutzer abmeldet, melde ich mich in meiner Identitätsverwaltungslösung (Cognito) ab und markiere sie als INACTIVE. Beachten Sie, dass ein Benutzer, der die API nicht innerhalb von 15 Minuten erreicht, keinen Eintrag mehr für ACTIVEseinen Benutzernamen hat und nicht mehr auf die API zugreifen kann und sich erneut anmelden muss, wofür er umgeleitet wird.

Bei diesem Ansatz sind viele Dinge zu beachten. Zum einen werden die Ergebnisse von Authorisierern häufig für einen bestimmten Zeitraum zwischengespeichert. Wenn Sie beispielsweise angeben, dass Sie das Ergebnis 5 Minuten lang zwischenspeichern, wird Ihr Benutzer möglicherweise innerhalb von 10 Minuten als Benutzer abgemeldet könnte den Cache anstelle des Authorizers treffen, wodurch der ACTIVEEintrag nicht aktualisiert wird .

Es ist auch wichtig, dass Sie sicherstellen, dass alles, was Sie zum Speichern verwenden, wenn ein bestimmter Benutzer ACTIVEverfügbar ist, hoch verfügbar ist und sich im Falle eines Fehlers schnell erholt.

Die Vorgehensweise bei der Verwendung eines Cache-Speichers auf diese Weise ähnelt der Nachrüstung der Token-Ungültigmachung für zustandslose Autorisierungsprotokolle wie OAuth2.

Wir verwenden diesen Ansatz seit einigen Monaten. Es scheint für uns gut zu funktionieren. Es kann eine nervige Anforderung sein, damit umzugehen. Ich hatte in der AWS-Welt erwartet, dass es einen gebrauchsfertigen Ansatz geben würde von der Box-Lösung dafür, aber es gab keine zu sprechen.

Snickers3192
quelle
Wir haben auch einen Pen-Test überstanden (; Hierher kam unsere Anforderung ursprünglich, unsere Anwendung ist ein auf Finanzdienstleistungen basierendes Produkt, und wir mussten dies als Anforderung implementieren.
Snickers3192