コンピューターをスリープ状態にしたユーザーをWebサイトからログアウトさせる


11

これは奇妙なものです。私たちはLaravelのWebサイトを持っており、このサイトにはユーザーごとにタイマーがあり、起動する前に15分間非アクティブになります。

これは、reactコンポーネントのページにあるタイマーを介して行いますが、期待どおりに機能しますが、今では新しい問題があります。ユーザーがログインしてラップトップのふたを閉じると、Webサイトはそれらを起動するはずです。銀行がこれを行い、学校や大学がこれを行い、政府機関もこれを行います。したがって、それは可能です。

laravel-websocketsライブラリとEcho を使用して、Webソケットを使用します。私が見たいのは:

  • ラップトップを閉じると、ログイン画面が表示されます。したがって、次にラップトップを開いてログインすると、ログイン画面にブラウザが表示されます。それはそれほど迅速に発生する必要はありませんが、基本的にページを更新するように指示する何かをフロントエンドに送信する方法が必要です。セッションが強制終了されると、15分のlaravelでセッションライフタイムを設定します。

一部の人々は他の同様の質問で提案しました:

最も人気のあるものは、Webソケットを使用していて、ユーザーが切断してから起動するのをリッスンしていますが、これで問題ありませんが、一時停止しているブラウザーにリクエストを送信してから起動するにはどうすればよいでしょうか。

requestIdleCallback()を見つけましたが、サイトにすでにハートビートタイマーがある場合は、これが必要だとは思いません。また、すべてのブラウザで機能するわけではありません。

私はこれを達成する方法についてここで非常に迷っています、私が与えることができる例は次のとおりです:

銀行にログインし、コンピューターをスリープ状態にして、15〜20分待ってからコンピューターを起動し、ログインして、銀行にログイン画面が表示されることを確認します。それが私が欲しいものです。しかし、私はそれを達成する方法を知りません。

バックエンドから「スリープ中」のブラウザにイベントを送信することはできません。はい、これはバックエンドのソリューションでなければなりませんが、フロントエンドを更新して、ラップトップを再起動したときにログアウト画面に表示されるようにする方法を教えてください。またはコンピュータ?


7
セッションクックの有効期限を「今+ 15分」に設定するだけです...最後の画面が引き続き表示される場合がありますが、Cookieの有効期限が切れている場合、そのセッションでは操作できません。そして、「ログイン画面へブート」 -私はかなり確信してOSの設定があることだと自動的に非アクティブの一定時間後にコンピュータ...ログアウト
ラースStegelitz

1
セッションCookieと同じタイムアウトで、サイトが読み込まれるたびにJavascriptタイマーを初期化できます...タイマーが「鳴る」場合、ユーザーは長期間非アクティブでした。次に、彼をログアウトし(AJAX呼び出し)、ブラウザをログイン画面または「非
アクティブの

1
わかりました。今すぐ回答を追加します。
Dato DT

1
これは役に立ちましたか?
Dato DT

1
@DatoDTいいえ、1つはlaravelを使用しており、2つは既にオーラリングポストで表現されているようにlaravelソケットを使用しています。私は本質的にララベルソリューションを探しています。
TheWebs

回答:


0

更新

WebSocketリクエストについては、Laravel WebSocketをで使用していると思いますpusherPusher.io はタイムアウトをサポートしていません。このサポート記事「チャネルのpusher-jsクライアントライブラリに接続タイムアウト機能を追加する予定はありますか?」を読むことができます。Laravelデバッグモード(APP_DEBUG=true 内部 .env)を有効にしlaravel-websockets、ターミナル(php artisan websockets:serve)から開始すると、テストして、出力ログイベントを確認できます。ラップトップの蓋を閉じようとしたり、コンピューターを休止状態(スリープ)に設定しようとしたりしても、このイベントに関するメッセージは表示されません。pusherプロトコルではできません。プレゼンスイベントがありますmember_removed 、しかしそれはあなたがタブを閉じたとき、またはログアウトしたときにのみトリガーされます。もちろん、あなたは存在チャンネルにあなたのクライアントのカスタムイベントをトリガすることができますが、あなたはまた、クライアント側にタイマー設定が必要であることを行うには、あなたがのためのサービスプロバイダを作成する必要がありますlaravel-websockets。このgithubの問題のようなサーバーを「への道を存在しWebhookを実装しますか?」

一部の人々は他の同様の質問で提案しました:

...

  • フロントエンドでタイマーを実行するには(ラップトップの蓋を閉じるとタイマーが停止します

これは、クライアントタイマーが休止状態で実行を停止するために発生し、以前の状態から続行されます。しかし、日付変数を使用して時間を節約した場合、コンピューターが休止状態になったときにその変数は更新されません。そのため、現在の時間と比較して重要な日付変数チェックすることで、いつスリープから抜けるかを知ることができます。差があり、タイマー間隔より大きくなります。

クライアントに時間ロジックを実装する

また、この関連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);

この簡単な例を確認できますが、ここでは115秒単位のログアウトを備えた2番目のタイマーを使用しています。ラップトップでふたを閉じてテストし、2 15秒後にもう一度開くと、多くのプログラムが実行されている場合、コンピューターはメモリ状態を保存して休止状態モードを完了して実行を停止するのに時間がかかります。

Webワーカーの例

Web Workers APIを使用して、より安全なWebワーカーを設定することもできます。

ページ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
  }
}

WebワーカーlogoutWorker.jsコード:

let clientSession = new Date();

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

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

こちらの同じ15秒数タイマー Webワーカーの例を確認することもできます


これは、15秒後にログアウトしますが、これが彼が探しているものかどうかはわかりません。
イスラムElshobokshy

@IslamElshobokshyあなたが正しい、キャッチをありがとう。clientSession変数を更新するのを忘れました。私の答えをもう一度確認できます。Webワーカーの例も追加しました。
Christos Lytras

それでも動作しないサンプルの例を更新してください。最初のものは15秒後にログアウトします。2番目はログアウトしません。
イスラムElshobokshy

@IslamElshobokshyもちろん更新しました。以前は問題がありましたが、現在は期待どおりに動作しています。?v=1最後にのようにparamを追加していない場合や追加している場合は、ページを修正してください。
Christos Lytras

1
優れた

0

まず、銀行のWebサイトが15分後にアクティビティなしでログアウトする理由を詳しく説明します。これは、セキュリティのためのPCI要件です。

PCI-DSS要件8.1.8

8.1.8セッションが15分以上アイドル状態であった場合、端末またはセッションを再度アクティブにするために、ユーザーに再認証を要求します。

これを実現するためのソリューションは、実際には想像以上に原始的です。Websocketを使用する必要も、クライアントのマシンの状態(スリープまたはアウェイクなど)を知る必要もありません。必要なのは、そのセッションを使用する現在の要求と同じセッションを使用する最後の要求の間の時間を把握し、それらの間隔が15分を超えないようにすることです。ユーザーである場合、ユーザーは再認証されます。そうでない場合は、リクエストを続行できます。

「セッションがタイムアウトしました」メッセージ

コンピュータがスリープ状態になり、ウェイクアップを再開したときに、セッションがタイムアウトしたというメッセージがどのように表示されるのか(そのように単純である場合)に疑問に思われるでしょう。この部分は一見シンプルです。

コンピュータがスリープ状態になると、ブラウザは実際にすべてのTCP / IP接続を切断し、JavaScriptエンジンのイベントループをシャットダウンします。したがって、タイマーは機能しません。しかし、ブラウザが再びウェイクアップすると、ページ自体を含むいくつかのものを更新しようとします。したがって、ページが更新されると、リクエストはサーバーに戻り、サーバーを呼び出してユーザーの再認証を要求します。

ただし、これは一部の銀行のWebサイトが行う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);


};

サーバー側でのセッション終了の処理

サーバー側でセッションの終了を処理するには、いくつかの方法があります。どちらを使用するかに応じて、さまざまな戦術が必要になります。1つは、PHPのデフォルトのセッションハンドラーを使用してsession.max_lifetime、15分後に有効期限が切れるように設定することです(これにより、サーバー側でセッションデータが完全に削除され、クライアントのCookieが無効になります)。

デフォルトのセッションハンドラーメカニズムを使用すると、使用するハンドラー(ファイル、memcached、redis、カスタムなど)に応じて問題が発生する可能性があります。

ファイル(デフォルトハンドラー)では、ガベージコレクションは次の2つの方法のいずれかで行われます。

  • ほとんどのDebianベースのシステムは、cronジョブを介して独自のGCを実行します(シナリオに最適です)
  • 他のディストリビューションでは、PHPのデフォルトのGCメカニズムがそれを処理します。これは、セッションファイルのファイルmtimeをチェックし、過去のファイルを削除するPHPへの各受信リクエストからの確率的結果に基づいていますsession.max_lifetime。このアプローチの問題は、トラフィックの少ないサイトではsession.gc_probability、GCを呼び出してセッションファイルをクリーンアップするのに十分なリクエストが(スコアに応じて)入るまで、セッションがサーバーに長時間滞在する可能性があることです。

memcachedおよびredisベースのハンドラーでは、この問題は発生しません。それらはメモリのパージを自動的に処理します。セッションは存続期間を過ぎても物理メモリに残っている可能性がありますが、デーモンはそれらにアクセスできません。セキュリティのためにこのビットが心配な場合は、保存されているセッションを暗号化するか、GCメカニズムをより厳密にメモリパージするキー/値ストアを見つけることができます。

カスタムセッションハンドラーを使用して、独自のGCメカニズムを構築する必要があります。SessionHandlerInterfaceあなたが実装したいgcメソッドをその手あなたのセッションの最大存続期間、あなたはセッションがこの間隔に基づいて寿命を過ぎた場合の検証のために責任があると、そこからあなたのガベージコレクションを行うと思います。

(クライアント側の非同期AJAXリクエストを介して)セッションTTLをチェックし、セッションの有効期限が切れた場合にJavaScriptがユーザーを再認証するように強制する応答を返す別のエンドポイントを設定することもできます。


0

したがって、IdeaはsetIntervalおよびSocketsの背後にあり、setIntervalはほとんどのブラウザーでサポートされており、JavaScript WbsocketApiはほとんどすべてのブラウザーでサポートされています。

簡単な概要:setInterval()-この関数の動作は、コンピューターがスリープ/サスペンド/ハイバネートモードのときに一時停止し、ウェイクアップモードのときにコンピューターが再開します。

次のコードは、最初に(おそらく同時に)次のことを行います。接続をリッスンするphp server_socketを開始します。

javascript websocket apiが2秒ごとにUnixタイムスタンプミリ秒で現在のタイムスタンプを送信するよりも、1秒は自由です。

その後、phpサーバーソケットはこの時間を取得し、比較する前の時間のようなものがあるかどうかを確認します。コードが最初にインスタンス化されるとき、phpは、前の時間のようにそれをjavascript websocketから送信された時間と比較するためのものを持っていないため、php 「prev_time」と呼ばれるセッションでこの時間を保存するだけで、javascriptソケットから別の時間データが受信されるのを待つため、ここで2番目のサイクルが開始されます。phpサーバーが新しい時間データをjavascript WebsocketApiから確認すると、この新しく受信した時間データと比較する前の時間と同じかどうかを確認します。これは、2番目のサイクルにいるため、phpが「prev_time」というセッションが存在するかどうかを確認することを意味します。存在し、その値を取得して以下を実行します$diff = $new_time - $prev_time、$ diffは2秒または2000ミリ秒になります。これは、setIntervalサイクルが2秒ごとに発生し、送信する時間形式がミリ秒であることを思い出してください。

phpよりもif($diff<3000)違いが3000未満かどうかを確認します。ユーザーがアクティブであることがわかっている場合は、この秒数を希望どおりに操作できます。ほぼ不可能であるネットワークでの遅延の可能性があるため、3000を選択します。ネットワークに来るので続けましょう。ユーザーがアクティブであるとphpが判断した場合、phpは「prev_time」セッションを$new_time新しく受信した値でリセットし、テスト目的でメッセージをJavaScriptソケットに送り返します。

しかし場合は$diff3000以上であることがその何かが私たちのsetIntervalを一時停止し、それが起こることができる唯一の方法があると私はすでに私がそうで、言って何を知っていると思う意味else(のロジックif($diff<3000))を使用すると、特定のセッションを破壊することで、あなたならば、ユーザーをログアウトすることができますリダイレクトしたい場合は、javacriptソケットにテキストを送信window.location = "/login"し、テキストに応じて実行されるロジックを作成できます。これがコードです。

まず、JavaScriptをロードするためのindex.htmlファイルです。

<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ソケットを次のコマンドで実行します。php -f server_socket.phpローカルホストに移動し、コンソールを開いてテストし、「あなたはアクティブです」または「あなたはアクティブではありません」というメッセージを確認します。 (あなたが眠りから来たとき); あなたの実行は、ユーザーがスリープ状態にあるときではなく、スリープ状態になるときに発生します


フォルダーを作成し、これをファイルにコピーして貼り付けるだけで、phpソケットを次のコマンドで実行します。php -f server_socket.php ローカルホストに移動し、コンソールを開いてテストし、「あなたはアクティブ」または「あなたはアクティブではありません」というメッセージを確認(あなたが眠りから来たとき); あなたの実行は、ユーザーがスリープ状態ではなくスリープ状態になるときに発生します。その瞬間、すべてがページファイル(windows)またはswap(linux)にキャッシュされます
Dato DT

0

銀行のログイン/ログアウトシステムがどのように機能するかについて、多くのことを説明しました。

ケース1:ユーザーがアクティブな場合、無制限の時間でユーザーにWebページにアクセスする

ユーザーがログインするたびに、バックエンドでタイマーを開始します(制限時間は何でも設定できます)、たとえば15分とします。今それは何を意味しますか?これは、ユーザーがWebページでアクティビティを実行しない場合、ログアウトすることを意味します。

これで、前からユーザーアクティビティをバックエンドに送信できます(ソケットまたはロングポーリングを使用して送信できます)。これにより、基本的にタイマーがリセットされ、ユーザーはいつでも好きなときにWebページをアクティブに使用できます。

ユーザーがPCをスリープ状態にした場合、タイマーはリセットされず、タイマーが終了したらセッションを無効にすることができます。

PCがスリープ状態になり次第、ユーザーセッションを無効にする場合は、セッション検証時間の制限を設定できます。たとえば、ユーザーがログインすると、10秒間のみ有効なセッションが作成されます。ユーザーアクティビティリクエストを受け取ったら、タイマーをリセットして新しいセッションキーを提供できます。

これがお役に立てば幸いです。ご不明な点がありましたらお知らせください。


-1

マシンがスリープ状態になったかどうかを検出するためのスクリプトを書きました。アイデアは、マシンがスリープ状態になると、すべてのスクリプトが停止するというものです。したがって、timeInterval内で現在時刻を追跡する場合。timeIntervalが現在時刻をトリガーするたびに、マイナス(-)は新しい時刻がtimeIntervalに十分に近いはずです。そのため、タイマーがX時間アイドルだったかどうかを確認する場合は、時間差がXより大きいかどうかを確認できます。

ブローの例では、コンピュータが15秒以上スリープ状態になっていたかどうかを確認します。コンピュータをスリープ状態にすると、すべてのプロセッサを考えるのにさらに15秒ほどかかることに注意してください。(MY PCでテストした場合)。

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

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

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

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

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

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

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


うまくいかない場合、なぜこれが機能しないのか説明してください
Lasithds

-1

AWS Cognitoを使用してまったく同じ要件をLambda AuthorizersとRedisで実装しました。この段階ではコードを共有できませんが、これらのコンポーネントでどのように実装されるかをすべて説明できます。同じ概念を他のコンポーネントでも使用できます非AWSコンポーネント。

まず、非アクティブなログアウトを実装する場合は、サーバー側で行う必要があります。まるで誰かが自分のコンピューターの電源をオフにしても、フロントエンドWebサイトはログアウトしません。ACTIVEユーザーの概念を使用しました。ユーザーが認証に成功すると、TTLが15分のRedisに、ユーザーとusername値のキーを持つエントリを格納しますACTIVE(特定のユーザーに対して同時に複数のセッションを許可する場合は、username + sessionidにすることができます)。

ユーザーがACTIVE有効なトークンを持っている場合のカスタムオーソライザーでは、保護されたリソースへのアクセスをユーザーに許可します。最も重要なのは、username&を使用してRedisにもう一度置くことですACTIVE

ユーザーがログアウトするたびに、自分のID管理ソリューション(Cognito)でログアウトし、ユーザーにのマークを付けますINACTIVE。ユーザーが15分以内にAPI ACTIVEにアクセスしないと、ユーザー名に対するエントリがなくなり、APIにアクセスできなくなり、再度サインインする必要があるため、リダイレクトされます。

このアプローチでは、多くの考慮事項があります。1つは、承認者が結果を一定期間キャッシュすることが多く、例として結果を5分間キャッシュすると、ユーザーはユーザーとして10分間ログオフされる可能性があります。ACTIVEエントリを更新しないオーソライザーの代わりにキャッシュにヒットする可能性があります。

また、特定のユーザーのACTIVE可用性が高く、障害が発生した場合に迅速に回復する場合は、保存に使用するものをすべて確認することも重要です。

この方法でキャッシュストアを使用する方法は、トークンの無効化をOAuth2などのステートレスな認証プロトコルに組み込む方法と似ています。

私たちはこのアプローチを数か月間使用してきましたが、うまくいくように見えます。処理するのは少し面倒な要件になる可能性があります。AWSの世界では、すぐに使用できることを期待していましたこのためのボックスソリューションですが、話すことはありませんでした。


私たちの要求が最初にどこから来たこれは、私たちのアプリケーションは、金融サービスベースの製品であり、我々は要件としてこれを実装する必要がありました。また、(ペンテストに耐えた。
Snickers3192
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.