Déconnectez un utilisateur d'un site Web lorsqu'il met son ordinateur en veille

11

C'est bizarre. Nous avons un site Web Laravel, et sur ce site, nous avons un minuteur par utilisateur, où ils obtiennent 15 minutes d'inactivité avant d'être démarrés.

Nous le faisons via une minuterie qui se trouve sur la page dans un composant React, cela fonctionne comme nous le voulons, mais nous avons maintenant un nouveau problème: si un utilisateur est connecté et ferme le couvercle de son ordinateur portable, le site Web devrait le démarrer . Les banques le font, les écoles et les universités le font, les sites gouvernementaux le font aussi. Il est donc possible, mais je ne sais pas comment.

Nous utilisons des sockets Web, en utilisant la bibliothèque laravel-websockets et Echo. Ce que j'aimerais voir se produire, c'est:

  • Une fois que vous avez fermé le démarrage de votre ordinateur portable, vous accédez à l'écran de connexion. Ainsi, la prochaine fois que vous ouvrirez l'ordinateur portable et que vous vous connecterez, vous verrez le navigateur sur l'écran de connexion. Cela ne doit pas se produire aussi rapidement, mais nous avons besoin d'un moyen d'envoyer quelque chose au front-end en leur disant essentiellement de rafraîchir la page, une fois la session interrompue, nous définissons la durée de vie de la session sur un laravel de 15 minutes.

Certaines personnes ont suggéré dans d'autres questions similaires:

  • créer un gestionnaire de socket Web personnalisé
  • Pour comparer le cookie de session (dans le navigateur) avec le cookie utilisateur à l'arrière.
  • Pour avoir une minuterie en cours d'exécution à l'avant (nous le faisons, il s'arrête juste lorsque vous fermez le couvercle de l'ordinateur portable)

Le plus populaire semble utiliser des sockets Web, écouter l'utilisateur se déconnecter puis les démarrer, ce qui est bien, mais comment envoyer une demande à un navigateur suspendu pour ensuite les démarrer?

J'ai trouvé requestIdleCallback () Mais encore une fois, je ne pense pas que c'est ce que je veux si j'ai déjà un chronomètre sur le site. Cela ne fonctionne pas non plus dans tous les navigateurs.

Je suis très perdu ici sur la façon d'y parvenir, l'exemple que je peux donner est:

Connectez-vous à votre banque, mettez votre ordinateur en veille, attendez 15 à 20 minutes, réveillez l'ordinateur, connectez-vous et voyez que votre banque vous a maintenant sur l'écran de connexion. Voilà ce que je veux . Mais je ne sais pas comment y parvenir.

Vous ne pouvez pas envoyer d'événements à un navigateur "en veille" à partir du back-end, et même si cela doit être une solution back-end, comment mettez-vous à jour le front-end, de sorte qu'ils soient sur l'écran de déconnexion lorsqu'ils réveillent l'ordinateur portable ou ordinateur?

TheWebs
la source
7
Il suffit de définir la date d'expiration de la session de cuisson sur "maintenant + 15 minutes" ... bien que vous puissiez toujours voir le dernier écran, vous ne pouvez pas agir dans cette session si le cookie a expiré. Et le "boot to login screen" - je suis à peu près sûr qu'il existe un paramètre de système d'exploitation qui déconnectera automatiquement un ordinateur après un certain temps d'inactivité ..
Lars Stegelitz
1
Vous pouvez lancer un timer Javascript chaque fois qu'un site est chargé, avec le même timeout que votre cookie de session ... si le timer "sonne", l'utilisateur est resté inactif pendant si longtemps. Vous devez ensuite le déconnecter (appel AJAX) et rediriger le navigateur vers l'écran de connexion ou l'écran "Désolé, nous vous avons déconnecté en raison de l'inactivité";)
Lars Stegelitz
1
D'accord, je l'ai fait, j'ajoute la réponse dès maintenant.
Dato DT
1
était-ce donc utile?
Dato DT
1
@DatoDT Non, un j'utilise laravel, deux j'utilise déjà des sockets laravel comme indiqué dans mon article d'ouverture, deux votre code est très compliqué, pas OOP, non testé et je ne l'utiliserais jamais. Je recherche essentiellement une solution laravel.
TheWebs

Réponses:

0

MISE À JOUR

Concernant la demande WebSocket, je suppose que vous utilisez Laravel WebSockets avec pusher. Pusher.io ne prend pas en charge le délai d'expiration , vous pouvez lire cet article de support " Envisagez -vous d'ajouter une fonctionnalité de délai d'expiration de connexion à la bibliothèque client des canaux pusher-js?" . Vous pouvez le tester si vous activez le mode de débogage de Laravel (à l' APP_DEBUG=true intérieur .env ) et commencez à laravel-websocketspartir du terminal ( php artisan websockets:serve) afin que vous puissiez voir les événements du journal de sortie. Si vous essayez de fermer le couvercle de l'ordinateur portable ou de mettre l'ordinateur en mode hibernation ( veille ), vous ne verrez aucun message concernant cet événement. Vous ne pouvez pas le faire avec le pusherprotocole. Il y a l' événement Présencemember_removed , mais cela ne se déclenche que lorsque vous fermez l'onglet ou que vous vous déconnectez. Bien sûr, vous pouvez déclencher votre événement personnalisé client sur le canal de présence, mais pour ce faire, vous avez également besoin d'une configuration de minuterie côté client et vous devrez créer un fournisseur de services pour le laravel-websocketsserveur comme ce problème github "Exister un moyen de implémenter des webhooks? " .

Certaines personnes ont suggéré dans d'autres questions similaires:

...

  • Pour avoir une minuterie en cours d'exécution à l'avant ( nous le faisons, elle s'arrête juste lorsque vous fermez le couvercle de l'ordinateur portable )

Cela se produit car les temporisateurs clients arrêtent l'exécution en veille prolongée, ils continuent donc à partir de là où ils étaient auparavant. Mais si vous utilisez une variable de date pour gagner du temps , cette variable ne sera pas mise à jour lorsque l'ordinateur se mettra en veille prolongée, ainsi vous saurez quand il sortira du sommeil en vérifiant cette variable de date qui, par rapport à l'heure actuelle, aura une importance significative différence et sera supérieure à l'intervalle de la minuterie.

Implémentation de la logique temporelle dans le client

Vous pouvez également voir cette implémentation dans cette Q / R associée : des navigateurs de bureau peuvent-ils détecter le moment où l'ordinateur sort du mode veille?

Vous pouvez configurer une minuterie dans le client pour qu'elle s'exécute chaque minute. Nous ne compterons pas sur l'intervalle de temporisation , mais à la place, cette temporisation vérifiera une variable de date de portée externe si l'intervalle de temps depuis la dernière temporisation est supérieur à 15minutes; si c'est le cas, cela signifie que le navigateur / JS a interrompu l'exécution pour une raison quelconque , éventuellement l'hibernation de l'appareil ( veille ), puis vous redirigez l'utilisateur vers la route de déconnexion.

Exemple de code client 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);

Vous pouvez vérifier cet exemple simple mais en utilisant un 1deuxième temporisateur avec 15déconnexion des secondes ici . Il est préférable de le tester sur un ordinateur portable en fermant le couvercle, puis de l'ouvrir à nouveau après 15 secondes par minute sur deux, car si vous avez de nombreux programmes en cours d'exécution, l'ordinateur prend un certain temps pour enregistrer l'état de la mémoire afin de terminer le mode d'hibernation et d'arrêter l'exécution.

Exemple de travailleurs Web

Vous pouvez même utiliser l' API Web Workers pour configurer un travailleur Web pour qu'il soit beaucoup plus sûr:

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

logoutWorker.jsCode de travail Web :

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

Vous pouvez également consulter l'exemple Web Worker avec la même 15minuterie de secondes ici .

Christos Lytras
la source
Cela vous déconnecte après 15 secondes, peu importe ce que vous pensez, pas sûr que ce soit ce qu'il cherche.
Islam Elshobokshy
@IslamElshobokshy vous avez raison, merci pour la capture. J'ai oublié de mettre à jour la clientSessionvariable. Vous pouvez vérifier ma réponse à nouveau, j'ai même ajouté un exemple de Web Worker.
Christos Lytras
Veuillez mettre à jour les exemples d'exemples qui ne fonctionnent toujours pas. Le premier vous déconnecte après 15 secondes quoi qu'il arrive. La seconde ne vous déconnecte jamais.
Islam Elshobokshy
@IslamElshobokshy Je l'ai bien sûr mis à jour. Avant, il y avait un problème, et maintenant cela fonctionne comme prévu. Veuillez actualiser la page si vous ne l'avez pas fait ou peut-être ajouter un paramètre comme ?v=1à la fin.
Christos Lytras
1
Great Solution + 3
AmerllicA
0

Tout d'abord, expliquons pourquoi les sites Web bancaires vous déconnectent après 15 minutes sans activité. C'est une exigence PCI pour la sécurité.

Exigence PCI-DSS 8.1.8 :

8.1.8 Si une session est inactive depuis plus de 15 minutes, demander à l'utilisateur de s'authentifier à nouveau pour réactiver le terminal ou la session.

Pour y parvenir, la solution est en réalité beaucoup plus primitive que vous ne l'imaginez . Il ne nécessite ni l'utilisation de websockets ni aucune connaissance de l'état de la machine du client (veille ou éveillé ou autre). Il suffit de connaître l'intervalle de temps entre la demande en cours utilisant cette session et la dernière demande en utilisant la même session et de s'assurer qu'ils ne sont pas distants de plus de 15 minutes. S'ils le sont, l'utilisateur doit être réauthentifié. Si ce n'est pas le cas, vous pouvez poursuivre la demande.

Le message "session expirée"

Vous vous demandez probablement (si c'est aussi simple) comment le message de délai d'expiration de la session apparaît lorsque vous mettez l'ordinateur en veille et le réveillez. Cette partie est d'une simplicité trompeuse.

Lorsque l'ordinateur est mis en veille, le navigateur déconnecte réellement toutes les connexions TCP / IP, ce qui à son tour arrête la boucle d'événements dans le moteur javascript. Les minuteries ne fonctionnent donc pas. Mais lorsque le navigateur se réveille à nouveau, il tente de rafraîchir certaines choses, y compris la page elle-même. Ainsi, lorsque la page est actualisée, la demande revient au serveur invoquant le serveur pour demander à l'utilisateur de s'authentifier à nouveau.

Cependant, cela ne tiendra pas compte du mode de message javascript (si c'est ce à quoi vous faites référence) que font certains sites bancaires. De plus, tous les navigateurs n'effectuent pas une actualisation matérielle de la page dans tous les scénarios. Une autre approche peut donc être adoptée. Plutôt que d'avoir un minuteur dans le navigateur qui expire après 15 minutes, vous pouvez simplement stocker le temps de chargement de la page en javascript comme horodatage et avoir un intervalle de 1 seconde qui compare cet horodatage à l'horodatage actuel de l'ordinateur. S'ils sont espacés de plus de 15 minutes, la session doit être terminée.

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


};

Même si l'ordinateur se met en veille et que le minuteur s'arrête, la session finira par expirer du côté serveur ( voir la section ci-dessous pour plus de détails ) et lorsque l'ordinateur se réveillera à nouveau, le minuteur avec un intervalle de 1 seconde redémarrera finalement, invoquant le (comme si l'utilisateur avait expiré pendant que l'ordinateur dormait). Le temps perdu entre le moment où l'ordinateur s'est endormi et le moment où l'ordinateur se réveille n'a pas d'importance car l'horodatage restera en mémoire. La déconnexion entre le client et le serveur est sans importance car ils n'ont pas besoin de communiquer ces informations pour que la session se termine correctement côté serveur. Le serveur peut effectuer sa propre récupération de place et terminer la session sans communication du client (c'est-à-dire de manière asynchrone ).

Croyez-le ou non, les banques ne se soucient pas de l'activité à l'intérieur du client. Ils ne se soucient que de l'activité de demande au serveur. Donc, si vous vous demandez comment gardent-ils la session vivante pendant plus de 15 minutes lorsque l'utilisateur est sur la même page pendant aussi longtemps, ils envoient simplement une demande AJAX en arrière-plan pour actualiser la session après avoir demandé à l'utilisateur s'ils continuent veulent continuer.

Cela peut être fait dans le même onloadrappel d'événement que nous avons utilisé précédemment, comme ceci:

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


};

Gestion de la fin de session côté serveur

Pour gérer la fin de session côté serveur, il existe plusieurs approches. Selon celui que vous utilisez, vous aurez besoin de différentes tactiques. La première consiste à utiliser le gestionnaire de session par défaut de PHP et à définir l' session.max_lifetimeexpiration après 15 minutes (cela supprime les données de session entièrement côté serveur, ce qui invalide le cookie du client).

Si vous laissez le mécanisme de gestionnaire de session par défaut le faire, vous pouvez rencontrer des problèmes en fonction du gestionnaire utilisé (fichiers, memcached, redis, custom, etc.).

Avec les fichiers (gestionnaire par défaut), le garbage collection se déroule de deux manières:

  • La plupart des systèmes basés sur Debian font leur propre GC via un travail cron (ce qui fonctionne très bien pour votre scénario)
  • D'autres distributions permettent au mécanisme de GC par défaut de PHP de le gérer, qui est basé sur un résultat probabiliste de chaque demande entrante vers PHP qui vérifie les mtime de fichier sur les fichiers de session et supprime ceux après leur session.max_lifetime. Le problème avec cette approche est que sur les sites à faible trafic, une session peut potentiellement rester longtemps sur le serveur jusqu'à ce que suffisamment de demandes arrivent (en fonction du session.gc_probabilityscore) pour invoquer le GC pour nettoyer les fichiers de session.

Avec les gestionnaires basés sur memcached et redis, vous n'avez pas ce problème. Ils géreront automatiquement la purge de la mémoire. Les sessions peuvent toujours rester dans la mémoire physique pendant un certain temps au-delà de leur durée de vie, mais le démon ne pourra pas y accéder. Si vous êtes préoccupé par ce bit pour la sécurité, vous pouvez crypter vos sessions au repos ou trouver un magasin de clés / valeurs doté d'un mécanisme GC de purge de mémoire plus strict.

Avec un gestionnaire de session personnalisé, vous devrez créer votre propre mécanisme GC. Grâce à SessionHandlerInterfacevous souhaitez mettre en œuvre une gcméthode qui vous la main intervalle de durée de vie maximale de la session et que vous seriez responsable de vérifier si la session a dépassé sa durée de vie en fonction de cet intervalle et faites votre collecte des ordures à partir de là.

Vous pouvez également configurer un point de terminaison distinct qui vérifie le TTL de la session (via une demande AJAX asynchrone côté client) et renvoie une réponse si la session a expiré (forçant le javascript à ré-authentifier l'utilisateur).

Sherif
la source
0

Donc, Idea est derrière setInterval et Sockets, setInterval est pris en charge dans la plupart des navigateurs et javascript WbsocketApi est pris en charge dans presque tous les navigateurs.

Bref aperçu: setInterval () - ce comportement de fonction suit lorsque votre ordinateur est en mode veille / suspendu / hibernation il est en pause et lorsque vous êtes en mode réveil, il reprend lui-même.

Le code suivant fait ce qui suit, au début (peut-être en même temps mais) il démarre php server_socket en écoutant les connexions,

que javascript websocket api envoie l'horodatage actuel en horodatage Unix millisecondes toutes les 2 secondes, vous pouvez avoir 1 seconde, c'est à vous.

après que le socket du serveur php obtient cette fois-ci et vérifie s'il a quelque chose comme l'heure précédente à comparer, lorsque le code est instancié pour la première fois, php n'a rien de semblable à l'heure précédente pour le comparer à l'heure qui a été envoyée à partir de websocket javascript, donc php ne fait rien mais enregistre ce temps dans la session appelée «prev_time» et attend qu'une autre donnée de temps soit reçue de la socket javascript, donc ici commence le deuxième cycle. lorsque le serveur php charge de nouvelles données temporelles de javascript WebsocketApi, il vérifie qu'il a quelque chose comme l'heure précédente à comparer à ces données temporelles nouvellement reçues, cela signifie que php vérifie si une session appelée 'prev_time' existe, car nous sommes dans le deuxième cycle php découvre que il existe, saisit sa valeur et suit$diff = $new_time - $prev_time, $ diff sera de 2 secondes ou 2000 millisecondes, car n'oubliez pas que notre cycle setInterval se produit toutes les 2 secondes et que le format d'heure que nous envoyons est en millisecondes,

que php vérifie if($diff<3000)si la différence est inférieure à 3000 si elle sait que l'utilisateur est actif, encore une fois vous pouvez manipuler ces secondes comme vous le souhaitez, je choisis 3000 car une latence possible dans le réseau qui est presque impossible mais vous savez que je suis toujours prudent quand il s'agit de réseaux, alors continuons, lorsque php détermine que l'utilisateur est actif, php réinitialise simplement la session 'prev_time' avec la valeur $new_timequi vient d'être reçue et juste à des fins de test, il renvoie un message à la socket javascript,

mais s'il $diffest supérieur à 3000, cela signifie que quelque chose a interrompu notre setInterval et qu'il n'y a qu'une seule façon que cela puisse se produire et je pense que vous savez déjà ce que je dis, donc dans la elselogique de ( if($diff<3000)) vous pouvez déconnecter l'utilisateur en détruisant une session spécifique et si vous voulez rediriger vous pouvez envoyer du texte à la socket javacript et créer une logique qui s'exécutera en window.location = "/login"fonction du texte, ça y est voici le code:

D'abord c'est le fichier index.html juste pour charger javascript:

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

alors c'est javascript, il n'est pas vraiment joliment codé mais vous pouvez comprendre LIRE LES COMMENTAIRES ILS SONT IMPORTANT:

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

maintenant, voici une partie du code php, ne vous inquiétez pas, il y a aussi du code complet, mais cette partie est en fait ce qui fait les travaux mentionnés ci-dessus, vous rencontrerez également d'autres fonctions, mais elles sont destinées au décodage et au travail avec des sockets javascript, donc c'est vraiment la bonne chose LISEZ COMMENTAIRES ILS SONT IMPORTANTS:

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

?>

Et voici le code complet de 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;
}

NOTE LISEZ-LE: la $new_timevariable est $jsTimedans le code

créez un dossier et copiez et collez-le dans des fichiers exécutez php socket avec la commande: php -f server_socket.php allez sur l'hôte local et testez-le pour ouvrir la console pour voir les messages, il dira "vous êtes actif" ou "vous n'êtes pas actif" (quand tu reviens du sommeil); votre exécutable se produira lorsque l'utilisateur sortira du sommeil et non lorsqu'il sera en veille car à ce moment tout est mis en cache dans le fichier d'échange (windows) ou dans swap (linux)

Dato DT
la source
créez un dossier et copiez et collez-le dans des fichiers exécutez php socket avec la commande: php -f server_socket.php allez à l' hôte local et testez-le pour ouvrir la console pour voir les messages, il dira "vous êtes actif" ou "vous n'êtes pas actif" (quand tu reviens du sommeil); votre exécutable se produira lorsque l'utilisateur sortira du sommeil et non lorsqu'il sera en veille car à ce moment tout est mis en cache dans le fichier d'échange (windows) ou dans swap (linux)
Dato DT
0

Je pense que j'ai une idée, vous avez beaucoup discuté du fonctionnement du système de connexion / déconnexion bancaire.

Cas 1: accès de la page Web à l'utilisateur pour une durée illimitée si l'utilisateur est actif

Chaque fois qu'un utilisateur s'est connecté, démarrez une minuterie sur votre backend (définissez la limite de temps comme vous le souhaitez), disons 15 minutes. Maintenant qu'est-ce que cela signifie ?? Cela signifie que si l'utilisateur n'effectue aucune activité sur la page Web, nous le déconnecterons.

Maintenant, de l'avant, vous pouvez envoyer l'activité de l'utilisateur à votre backend (peut être envoyée à l'aide d'une socket ou d'une longue interrogation), ce qui réinitialisera essentiellement le minuteur et l'utilisateur pourra utiliser la page Web activement pendant la durée de son choix.

Si l'utilisateur met son PC en veille, le minuteur ne se réinitialise pas et vous pouvez invalider la session une fois le minuteur terminé.

Si vous souhaitez invalider la session utilisateur dès qu'ils mettent leur PC en veille, vous pouvez définir la limite de la durée de validation de la session. Par exemple, lorsque l'utilisateur se connecte, nous créons la session qui ne sera valide que pendant 10 secondes, et une fois que nous recevons la demande d'activité de l'utilisateur, nous pouvons réinitialiser le minuteur et fournir une nouvelle clé de session.

J'espère que ceci vous aide. Faites-moi savoir si vous avez des questions.

Harsh Srivastava
la source
-1

J'ai écrit un script pour détecter si la machine s'est endormie. L'idée est que lorsque la machine est en mode veille, tous les scripts s'arrêtent. Par conséquent, si nous gardons une trace de l'heure actuelle dans un intervalle de temps. Chaque fois que timeInterval déclenche l'heure actuelle moins (-), la nouvelle heure doit être suffisamment proche de timeInterval. Par conséquent, si nous voulons vérifier si la minuterie était inactive pendant le temps X, nous pouvons vérifier si la différence de temps est supérieure à X.

Un exemple vérifie si l'ordinateur a été mis en veille pendant plus de 15 secondes. Veuillez noter que lorsque vous mettez l'ordinateur en veille, il faut environ 15 secondes supplémentaires pour concevoir tous les processeurs. (Lors d'un test sur MON 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
la source
Veuillez expliquer pourquoi cela ne fonctionnerait pas, si ce n'est pas le cas dans votre cas
Lasithds
-1

J'ai implémenté exactement la même exigence en utilisant AWS Cognito, avec Lambda Authorizers, & Redis, je ne peux pas partager le code à ce stade mais je peux vous dire tout comment il est implémenté avec ces composants, les mêmes concepts peuvent être utilisés avec d'autres composants non AWS.

Tout d'abord avec l'implémentation d'une déconnexion d'inactivité, vous devrez le faire côté serveur, comme si quelqu'un éteignait simplement son ordinateur, le site Web frontal ne les déconnecterait pas. J'ai utilisé le concept d' ACTIVEutilisateurs. Lorsque les utilisateurs s'authentifient avec succès, je stocke avec un TTL de 15 minutes dans Redis une entrée avec une clé de leur usernameet une valeur de ACTIVE(il peut s'agir de nom d'utilisateur + identifiant de session si vous souhaitez autoriser plusieurs sessions pour un utilisateur donné en même temps).

Dans mes Authorizers personnalisés lorsqu'un utilisateur est ACTIVE& ils ont un Token valide, je leur accorde l'accès à la ressource protégée ET surtout, je fais une autre mise dans Redis avec le username& ACTIVE.

Chaque fois que l'utilisateur se déconnecte, je le déconnecte dans ma solution de gestion des identités (Cognito) et je le marque comme INACTIVE. Notez que si un utilisateur n'atteint pas l'API dans les 15 minutes, il n'aura plus d'entrée ACTIVEcontre son nom d'utilisateur et ne pourra plus accéder à l'API et devra se reconnecter, ce pour quoi il sera redirigé.

Il y a beaucoup de choses à considérer avec cette approche, pour une chose souvent, les Autorisateurs mettent en cache les résultats pendant un certain temps, et si par exemple vous cachez le résultat pendant 5 minutes à titre d'exemple, votre utilisateur peut être déconnecté en 10 minutes en tant qu'utilisateur pourrait atteindre le cache au lieu de l'autorisateur qui ne rafraîchirait pas l' ACTIVEentrée.

Il est également important de vous assurer que tout ce que vous utilisez pour stocker si un utilisateur donné ACTIVEest hautement disponible et récupérera rapidement en cas de défaillance.

L'approche de l'utilisation d'une mémoire cache de cette manière est similaire à la façon dont l'invalidation de jeton est mise à niveau vers des protocoles d'autorisation sans état tels que OAuth2.

Nous utilisons cette approche depuis quelques mois maintenant, cela semble bien fonctionner pour nous, cela peut être un peu gênant à gérer, je m'attendais à AWS world qu'il y aurait un prêt à utiliser de la solution de boîte pour cela, mais il n'y en avait pas de parler.

Snickers3192
la source
Nous avons également survécu à un test de plume (; c'est de là que venait notre exigence au départ, notre application est un produit basé sur les services financiers, et nous avons dû l'implémenter comme une exigence.
Snickers3192