Đăng xuất người dùng khỏi trang web khi họ đặt máy tính của họ ở chế độ ngủ


11

Đây là một trong những kỳ lạ. Chúng tôi có một trang web Laravel và trên trang web cho biết chúng tôi có một bộ đếm thời gian cho mỗi người dùng, nơi họ có được 15 phút không hoạt động trước khi được khởi động.

Chúng tôi thực hiện việc này thông qua một bộ đếm thời gian nằm trên trang trong một thành phần phản ứng, nó hoạt động như chúng tôi muốn, nhưng bây giờ chúng tôi có một vấn đề mới: Nếu người dùng đăng nhập và đóng nắp máy tính xách tay của họ, trang web sẽ khởi động chúng . Các ngân hàng làm điều này, Trường học và Đại học làm điều này, các trang web của Chính phủ cũng làm điều này. Vì vậy, nó là có thể, chỉ không chắc chắn làm thế nào.

Chúng tôi sử dụng ổ cắm web, sử dụng thư viện laravel-websockets và Echo. Những gì tôi muốn thấy xảy ra là:

  • Khi bạn đóng máy tính xách tay của bạn, bạn vào màn hình đăng nhập. Vì vậy, lần tới khi bạn mở máy tính xách tay và đăng nhập, và xem trình duyệt bạn đang ở trên màn hình đăng nhập. Điều đó không phải xảy ra nhanh chóng, nhưng chúng tôi cần một cách để gửi một cái gì đó lên mặt trước về cơ bản bảo họ làm mới trang, một khi phiên bị giết, chúng tôi đặt thời gian tồn tại của phiên là 15 phút.

Một số người đã đề xuất trong các câu hỏi tương tự khác:

  • để tạo một trình xử lý ổ cắm web tùy chỉnh
  • Để so sánh cookie phiên (trong trình duyệt) với cookie người dùng ở mặt sau.
  • Để có một bộ đếm thời gian chạy ở mặt trước (chúng tôi làm, nó chỉ dừng lại khi bạn đóng nắp máy tính xách tay)

Ứng dụng phổ biến nhất dường như đang sử dụng các ổ cắm web, lắng nghe người dùng ngắt kết nối và sau đó khởi động chúng, điều này tốt và tất cả, nhưng sau đó, làm thế nào để bạn gửi yêu cầu đến một trình duyệt bị treo để khởi động chúng?

Tôi đã tìm thấy requestIdleCallback () Nhưng một lần nữa, tôi không nghĩ đây là điều tôi muốn nếu tôi đã có đồng hồ đo nhịp tim trên trang web. Nó cũng không hoạt động trong tất cả các trình duyệt.

Tôi rất lạc lõng ở đây về cách thực hiện điều này, ví dụ tôi có thể đưa ra là:

Đăng nhập vào ngân hàng của bạn, đặt máy tính của bạn vào chế độ ngủ, đợi 15-20 phút, đánh thức máy tính, đăng nhập và thấy ngân hàng của bạn hiện có bạn trên màn hình đăng nhập. Đó là những gì tôi muốn . Nhưng tôi không biết làm thế nào để thực hiện điều đó.

Bạn không thể gửi các sự kiện đến trình duyệt "ngủ" từ phía sau và trong khi có, đây sẽ là một giải pháp mặt sau, làm thế nào để bạn cập nhật giao diện người dùng sau đó, để chúng ở trên màn hình đăng xuất khi họ đánh thức lại máy tính xách tay hay máy tính?


7
Chỉ cần đặt ngày hết hạn của phiên là "bây giờ + 15 phút" ... mặc dù bạn vẫn có thể thấy màn hình cuối cùng, bạn không thể hành động trong phiên đó nếu cookie đã hết hạn. Và "khởi động để đăng nhập màn hình" - Tôi khá chắc chắn rằng có một cài đặt HĐH sẽ tự động đăng xuất máy tính sau một thời gian không hoạt động nhất định ..
Lars Stegelitz

1
Bạn có thể khởi tạo bộ hẹn giờ Javascript bất cứ khi nào một trang web được tải, cùng thời gian chờ với cookie phiên của bạn ... nếu bộ hẹn giờ "đổ chuông", người dùng không hoạt động quá lâu. Sau đó, bạn sẽ đăng xuất anh ấy (cuộc gọi AJAX) và chuyển hướng trình duyệt đến màn hình đăng nhập hoặc màn hình "xin lỗi, chúng tôi đã đăng xuất bạn do không hoạt động";)
Lars Stegelitz

1
Được rồi tôi đã làm nó Tôi đang thêm câu trả lời ngay bây giờ.
Dato DT

1
vậy điều này có hữu ích không?
Dato DT

1
@DatoDT Không, Một tôi sử dụng laravel, hai Tôi đã sử dụng ổ cắm laravel như thể hiện trong bài mở đầu của tôi, hai mã của bạn rất lộn xộn, không phải OOP, không được kiểm tra và tôi sẽ không bao giờ sử dụng nó. Tôi chủ yếu tìm kiếm một giải pháp laravel.
TheWebs

Câu trả lời:


0

CẬP NHẬT

Về yêu cầu WebSocket, tôi giả sử bạn đang sử dụng Laravel WebSockets với pusher. Pizer.io không hỗ trợ thời gian chờ , bạn có thể đọc bài viết hỗ trợ này "Bạn có kế hoạch thêm tính năng hết thời gian kết nối vào thư viện máy khách Kênh pizer-js không?" . Bạn có thể kiểm tra nếu bạn bật chế độ gỡ lỗi Laravel ( APP_DEBUG=true bên trong .env ) và bắt laravel-websocketsđầu từ terminal ( php artisan websockets:serve) để bạn có thể xem các sự kiện nhật ký đầu ra. Nếu bạn cố gắng đóng nắp máy tính xách tay hoặc đặt máy tính ở chế độ ngủ đông ( ngủ ), bạn sẽ không thấy bất kỳ tin nhắn nào liên quan đến sự kiện này. Bạn không thể làm điều đó với pushergiao thức. Có sự kiện hiện diệnmember_removed , nhưng điều đó chỉ kích hoạt khi bạn đóng tab hoặc bạn đăng xuất. Tất nhiên, bạn có thể kích hoạt sự kiện tùy chỉnh máy khách của mình tới kênh hiện diện, nhưng để làm được điều đó, bạn cũng cần thiết lập hẹn giờ cho phía máy khách và bạn sẽ phải tạo một nhà cung cấp dịch vụ cho laravel-websocketsmáy chủ như vấn đề github này "Tồn tại thực hiện webhooks? " .

Một số người đã đề xuất trong các câu hỏi tương tự khác:

...

  • Để có một bộ đếm thời gian chạy ở mặt trước ( chúng tôi làm, nó chỉ dừng lại khi bạn đóng nắp máy tính xách tay )

Điều đó xảy ra bởi vì bộ định thời của máy khách dừng thực thi chế độ ngủ đông, do đó chúng tiếp tục từ nơi chúng ở trước đó. Nhưng nếu bạn sử dụng biến ngày để tiết kiệm thời gian , biến đó sẽ không được cập nhật khi máy tính chuyển sang chế độ ngủ đông, do đó bạn sẽ biết khi nào nó tắt khi ngủ bằng cách kiểm tra biến ngày đó so với thời gian hiện tại sẽ có ý nghĩa sự khác biệt và sẽ lớn hơn khoảng thời gian hẹn giờ.

Thực hiện logic thời gian trong máy khách

Bạn cũng có thể thấy triển khai này đối với Hỏi / Đáp liên quan này : Bất kỳ trình duyệt máy tính để bàn nào có thể phát hiện khi máy tính tiếp tục ngủ?

Bạn có thể thiết lập một bộ đếm thời gian trong máy khách để chạy mỗi phút. Chúng tôi sẽ không dựa vào khoảng thời gian hẹn giờ , nhưng thay vào đó, bộ hẹn giờ sẽ kiểm tra biến ngày phạm vi bên ngoài nếu khoảng thời gian kể từ lần hẹn giờ cuối cùng lớn hơn 15phút; nếu đúng như vậy, điều đó có nghĩa là trình duyệt / JS tạm dừng thực thi vì một số lý do , có thể là ngủ đông thiết bị ( ngủ ) và sau đó bạn chuyển hướng người dùng đến tuyến đăng xuất.

Ví dụ mã máy khách 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);

Bạn có thể kiểm tra ví dụ đơn giản này nhưng sử dụng 1bộ đếm thời gian thứ hai với 15đăng xuất giây tại đây . Tốt nhất để kiểm tra nó trên máy tính xách tay có nắp đậy và sau đó mở lại sau 15 giây một phút, bởi vì nếu bạn có nhiều chương trình đang chạy, máy tính sẽ mất một thời gian để lưu trạng thái bộ nhớ để hoàn thành chế độ ngủ đông và tạm dừng thực hiện.

Ví dụ công nhân web

Thậm chí, bạn có thể sử dụng API của Web Worker để thiết lập một nhân viên web an toàn hơn nhiều:

Mã trang:

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.jsMã nhân viên 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);

Bạn cũng có thể kiểm tra ví dụ Web Worker với cùng một 15bộ đếm thời gian giây ở đây .


Điều này giúp bạn thoát ra sau 15 giây bất kể là gì, không chắc chắn rằng đây là thứ anh ấy đang tìm kiếm.
Hồi giáo Elshobokshy

@IslamElshobokshy bạn nói đúng, cảm ơn vì đã nắm bắt. Tôi quên cập nhật clientSessionbiến. Bạn có thể kiểm tra câu trả lời của tôi một lần nữa, tôi thậm chí đã thêm một ví dụ về Công nhân web.
Christos Lytras

Vui lòng cập nhật các ví dụ mẫu vẫn không hoạt động. Đầu tiên đăng xuất bạn sau 15 giây không có vấn đề gì. Thứ hai không bao giờ đăng xuất bạn.
Hồi giáo Elshobokshy

@IslamElshobokshy Tôi đã cập nhật nó tất nhiên. Trước đây nó có một vấn đề, và bây giờ nó hoạt động như mong đợi. Vui lòng giới thiệu lại trang nếu bạn chưa hoặc có thể thêm thông số thích ?v=1vào cuối.
Christos Lytras

1
Giải pháp tuyệt vời + 3
AmerllicA

0

Trước tiên, hãy mở rộng lý do tại sao các trang web Ngân hàng đăng xuất bạn sau 15 phút mà không hoạt động. Đó là một yêu cầu PCI về bảo mật.

Yêu cầu PCI-DSS 8.1.8 :

8.1.8 Nếu một phiên không hoạt động trong hơn 15 phút, yêu cầu người dùng xác thực lại để kích hoạt lại thiết bị đầu cuối hoặc phiên.

Để đạt được điều này , giải pháp thực sự nguyên thủy hơn nhiều so với bạn tưởng tượng . Nó không yêu cầu sử dụng websockets cũng như không biết gì về trạng thái của máy của khách hàng (ngủ hay thức hay nói cách khác). Tất cả những gì được yêu cầu là biết thời gian giữa yêu cầu hiện tại sử dụng phiên đó và yêu cầu cuối cùng sử dụng cùng một phiên và đảm bảo chúng không cách nhau quá 15 phút. Nếu họ là người dùng sẽ được xác thực lại. Nếu họ không bạn có thể tiến hành yêu cầu.

Thông báo "hết thời gian"

Sau đó, có lẽ bạn đang tự hỏi (nếu nó đơn giản) thì thông báo hết thời gian phiên xuất hiện như thế nào khi bạn đặt máy tính ngủ và đánh thức nó lại. Phần này là đơn giản.

Khi máy tính được chuyển sang chế độ ngủ, trình duyệt thực sự ngắt kết nối tất cả các kết nối TCP / IP, từ đó tắt vòng lặp sự kiện trong công cụ javascript. Vì vậy, bộ hẹn giờ không hoạt động. Nhưng khi trình duyệt thức dậy một lần nữa, nó cố gắng làm mới một số thứ, bao gồm cả trang đó. Vì vậy, khi trang được làm mới, yêu cầu quay trở lại máy chủ gọi máy chủ để yêu cầu người dùng xác thực lại.

Tuy nhiên, điều này sẽ không giải thích cho phương thức tin nhắn javascript (nếu đó là những gì bạn đang đề cập đến) mà một số trang web ngân hàng làm. Ngoài ra, không phải tất cả các trình duyệt đều làm mới cứng trên trang trong tất cả các tình huống. Vì vậy, một cách tiếp cận khác có thể được thực hiện. Thay vì có một bộ đếm thời gian trong trình duyệt hết thời gian sau 15 phút, bạn chỉ cần lưu thời gian tải trang trong javascript dưới dạng dấu thời gian và có thời gian chờ 1 giây so sánh dấu thời gian đó với dấu thời gian hiện tại của máy tính. Nếu chúng cách nhau hơn 15 phút, phiên nên chấm dứt.

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


};

Ngay cả khi máy tính chuyển sang chế độ ngủ và bộ hẹn giờ dừng, phiên cuối cùng sẽ hết thời gian ở phía máy chủ ( xem phần bên dưới để biết chi tiết ) và khi máy tính thức dậy một lần nữa, bộ hẹn giờ với khoảng thời gian 1 giây cuối cùng sẽ khởi động lại, gọi tin nhắn (như thể người dùng đã hết thời gian trong khi máy tính đang ngủ). Thời gian bị mất giữa thời gian máy tính đi ngủ và thời gian máy tính thức dậy sẽ không còn quan trọng vì dấu thời gian sẽ còn trong bộ nhớ. Việc ngắt kết nối giữa máy khách và máy chủ là không quan trọng vì chúng không cần truyền đạt thông tin này để phiên kết thúc đúng ở phía máy chủ. Máy chủ có thể tự thu gom rác và chấm dứt phiên mà không cần giao tiếp từ máy khách (tức là không đồng bộ ).

Tin hay không Ngân hàng không quan tâm đến hoạt động bên trong của khách hàng. Họ chỉ quan tâm đến hoạt động yêu cầu đến máy chủ. Vì vậy, nếu bạn tự hỏi làm thế nào để họ duy trì phiên tồn tại trong hơn 15 phút khi người dùng ở cùng một trang trong thời gian đó, họ chỉ cần gửi yêu cầu AJAX trong nền để làm mới phiên sau khi hỏi người dùng nếu họ vẫn còn muốn tiếp tục.

Điều này có thể được thực hiện trong cùng một onloadcuộc gọi lại sự kiện mà chúng ta đã sử dụng trước đó như vậy:

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


};

Xử lý chấm dứt phiên ở phía máy chủ

Để xử lý việc chấm dứt phiên ở phía máy chủ, có một số cách tiếp cận. Tùy thuộc vào cái nào bạn sử dụng, bạn sẽ cần các chiến thuật khác nhau. Một người đang sử dụng trình xử lý phiên mặc định của PHP và thiết lập session.max_lifetimehết hạn sau 15 phút (điều này sẽ xóa hoàn toàn dữ liệu phiên ở phía máy chủ, do đó làm mất hiệu lực cookie của khách hàng).

Nếu bạn để cơ chế xử lý phiên mặc định thực hiện, bạn có thể gặp sự cố tùy thuộc vào trình xử lý nào được sử dụng (tệp, memcached, redis, custom, v.v.).

Với các tệp (trình xử lý mặc định), bộ sưu tập rác xảy ra theo một trong hai cách:

  • Hầu hết các hệ thống dựa trên Debian thực hiện GC của riêng chúng thông qua một công việc định kỳ (hoạt động rất tốt cho kịch bản của bạn)
  • Các phân phối khác cho phép cơ chế GC mặc định của PHP xử lý nó, dựa trên kết quả xác suất từ ​​mỗi yêu cầu đến PHP để kiểm tra tệp mtime trên các tệp phiên và xóa chúng qua các tệp của chúng session.max_lifetime. Vấn đề với cách tiếp cận này là trên các trang web có lưu lượng truy cập thấp, một phiên có thể có khả năng ngồi đó trên máy chủ trong một thời gian dài cho đến khi có đủ yêu cầu (tùy thuộc vào session.gc_probabilityđiểm số) để gọi GC để dọn sạch các tệp phiên.

Với các trình xử lý dựa trên memcached và redis, bạn không gặp phải vấn đề này. Họ sẽ xử lý thanh trừng bộ nhớ tự động. Các phiên có thể vẫn còn trong bộ nhớ vật lý trong một thời gian đã qua, nhưng daemon sẽ không thể truy cập chúng. Nếu bạn lo lắng về bit này để bảo mật, bạn có thể mã hóa các phiên của mình khi nghỉ ngơi hoặc tìm một kho lưu trữ khóa / giá trị có cơ chế thanh lọc bộ nhớ chặt chẽ hơn.

Với trình xử lý phiên tùy chỉnh, bạn sẽ phải xây dựng cơ chế GC của riêng mình. Thông qua việc SessionHandlerInterfacebạn thực hiện một gcphương pháp trao cho bạn khoảng thời gian tối đa của phiên và bạn có trách nhiệm xác minh xem phiên có vượt qua thời gian tồn tại hay không dựa trên khoảng thời gian này và thực hiện việc thu gom rác của bạn từ đó.

Bạn cũng có thể thiết lập một điểm cuối riêng biệt để kiểm tra phiên TTL (thông qua yêu cầu AJAX không đồng bộ ở phía máy khách) và gửi lại phản hồi nếu phiên đã hết hạn (buộc javascript phải xác thực lại người dùng).


0

Vì vậy, Idea đứng sau setInterval và Sockets, setInterval được hỗ trợ trong hầu hết các trình duyệt và WbsocketApi javascript được hỗ trợ trong hầu hết mọi trình duyệt.

Tổng quan ngắn gọn: setInterval () - hành vi chức năng này tuân theo khi máy tính của bạn ở chế độ ngủ / treo / ngủ đông, nó bị tạm dừng và khi bạn ở chế độ thức tỉnh, nó sẽ tự hoạt động trở lại.

Đoạn mã sau thực hiện như sau, lúc đầu (có thể cùng lúc nhưng) nó khởi động php server_socket lắng nghe các kết nối,

so với javascript websocket api gửi dấu thời gian hiện tại trong dấu thời gian Unix mili giây trong mỗi 2 giây bạn có thể có 1 giây tùy thuộc vào bạn.

Sau đó, ổ cắm máy chủ php sẽ nhận được thời gian này và kiểm tra xem nó có gì giống với lần trước không, khi mã được khởi tạo lần đầu tiên php không có gì giống như lần trước để so sánh với thời gian được gửi từ websocket javascript, vì vậy php không làm gì ngoài việc tiết kiệm thời gian này trong phiên gọi là 'trước_ thời gian' và chờ dữ liệu thời gian khác được nhận từ ổ cắm javascript, vì vậy ở đây bắt đầu chu kỳ thứ hai. Khi máy chủ php cắm dữ liệu thời gian mới từ javascript WebsocketApi, nó sẽ kiểm tra nó có bất cứ thứ gì giống như lần trước để so sánh với dữ liệu thời gian mới nhận này không, có nghĩa là php kiểm tra nếu phiên có tên là 'trước_ tồn tại', vì chúng ta đang ở trong chu kỳ thứ hai php phát hiện ra rằng nó tồn tại, lấy giá trị của nó và làm theo$diff = $new_time - $prev_time, $ diff sẽ là 2 giây hoặc 2000 milis giây vì hãy nhớ chu kỳ setInterval của chúng tôi diễn ra trong mỗi 2 giây và định dạng thời gian chúng tôi đang gửi là tính bằng milisecond,

hơn kiểm tra php if($diff<3000)nếu chênh lệch nhỏ hơn 3000 nếu biết rằng người dùng đang hoạt động, một lần nữa bạn có thể thao tác giây này theo ý muốn, tôi chọn 3000 vì độ trễ có thể xảy ra trong mạng gần như không thể nhưng bạn biết tôi luôn thận trọng khi nó liên quan đến các mạng, vì vậy hãy tiếp tục, khi php xác định rằng người dùng đang hoạt động php chỉ cần đặt lại phiên 'trước_ thời gian' với giá trị $new_timemới nhận được và chỉ nhằm mục đích thử nghiệm, nó sẽ gửi tin nhắn trở lại ổ cắm javascript,

nhưng nếu $diffnhiều hơn 3000 thì có nghĩa là có gì đó đã tạm dừng setInterval của chúng tôi và chỉ có cách nó có thể xảy ra và tôi nghĩ bạn đã biết tôi đang nói gì, vì vậy theo elselogic của ( if($diff<3000)) bạn có thể đăng xuất người dùng bằng cách hủy phiên cụ thể và nếu bạn muốn chuyển hướng bạn có thể gửi một số văn bản đến ổ cắm javacript và tạo một logic sẽ thực thi window.location = "/login"tùy thuộc vào văn bản, đó là mã:

Đầu tiên, nó là tệp index.html để tải javascript:

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

Sau đó, nó là javascript, nó không thực sự được mã hóa đẹp nhưng bạn có thể tìm ra Ý KIẾN ĐỌC NHỮNG ĐIỀU QUAN TRỌNG:

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

Bây giờ đây là một phần của mã php, đừng lo lắng vì cũng có mã đầy đủ nhưng phần này thực sự là những công việc được đề cập ở trên, bạn cũng sẽ gặp các chức năng khác nhưng chúng là để giải mã và làm việc với các ổ cắm javascript nên thực tế là đúng Ở đây ĐỌC Ý KIẾN HỌ LÀ QUAN TRỌNG:

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

?>

Và đây là mã đầy đủ của 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;
}

LƯU Ý ĐỌC CNTT: $new_timebiến nằm $jsTimetrong Code

tạo thư mục và chỉ cần sao chép và dán tệp này vào các tệp chạy php socket bằng lệnh: php -f server_socket.php đi đến localhost và kiểm tra bảng điều khiển mở để xem các thông báo sẽ cho biết "bạn đang hoạt động" hoặc "bạn không hoạt động" (khi bạn đi từ giấc ngủ); giám đốc điều hành của bạn sẽ xảy ra khi người dùng đến từ giấc ngủ chứ không phải khi họ đang ngủ vì tại thời điểm đó, mọi thứ được lưu trữ trong pagefile (windows) hoặc trao đổi (linux)


tạo thư mục và chỉ cần sao chép và dán tệp này vào các tệp chạy php socket bằng lệnh: php -f server_socket.php đi đến localhost và kiểm tra bảng điều khiển mở để xem các thông báo sẽ cho biết "bạn đang hoạt động" hoặc "bạn không hoạt động" (khi bạn đi từ giấc ngủ); giám đốc điều hành của bạn sẽ xảy ra khi người dùng đến từ giấc ngủ chứ không phải khi họ đang ngủ vì lúc đó mọi thứ được lưu trữ trong pagefile (windows) hoặc trao đổi (linux)
Dato DT

0

Tôi nghĩ rằng tôi có một ý tưởng, bạn đã thảo luận rất nhiều về cách hệ thống đăng nhập / đăng xuất ngân hàng hoạt động.

Trường hợp-1: Truy cập trang web tới người dùng trong thời gian không giới hạn nếu người dùng đang hoạt động

Bất cứ khi nào người dùng đăng nhập, Bắt đầu hẹn giờ trên phụ trợ của bạn (đặt giới hạn thời gian bất cứ điều gì bạn muốn), hãy nói 15 phút. Bây giờ nó có nghĩa là gì ?? Điều đó có nghĩa là nếu người dùng không thực hiện bất kỳ hoạt động nào trên trang web, thì chúng tôi sẽ đăng xuất anh ấy / cô ấy.

Bây giờ, từ phía trước, bạn có thể gửi hoạt động người dùng đến phụ trợ của mình (có thể được gửi bằng cách sử dụng ổ cắm hoặc bỏ phiếu dài), về cơ bản sẽ đặt lại bộ hẹn giờ và người dùng có thể sử dụng trang web một cách chủ động bất cứ lúc nào họ muốn.

Nếu người dùng đặt PC của họ ở chế độ ngủ, bộ hẹn giờ sẽ không được đặt lại và bạn có thể vô hiệu hóa phiên sau khi bộ hẹn giờ kết thúc.

Nếu bạn muốn vô hiệu hóa phiên người dùng ngay khi họ đặt máy tính của họ vào chế độ ngủ, bạn có thể đặt giới hạn thời gian xác thực phiên. Ví dụ: khi người dùng đăng nhập, chúng tôi sẽ tạo phiên chỉ có hiệu lực trong 10 giây và khi chúng tôi nhận được yêu cầu hoạt động của người dùng, chúng tôi có thể đặt lại bộ hẹn giờ và cung cấp khóa phiên mới.

Tôi hy vọng cái này sẽ giúp bạn. Hãy cho tôi biết nếu bạn có bất kỳ câu hỏi.


-1

Tôi đã viết một kịch bản để phát hiện nếu máy đi ngủ. Ý tưởng là khi máy đang trong tâm trạng ngủ, tất cả các tập lệnh sẽ dừng lại. Do đó, nếu chúng tôi theo dõi thời gian hiện tại trong một khoảng thời gian. Mỗi khi timeInterval kích hoạt thời gian hiện tại trừ (-) thời gian mới sẽ đủ gần với timeInterval. Do đó, nếu chúng tôi muốn kiểm tra xem bộ đếm thời gian có rảnh trong thời gian X không, chúng tôi có thể kiểm tra xem chênh lệch thời gian có nhiều hơn X hay không.

Ví dụ kiểm tra thổi nếu máy tính được đưa vào chế độ ngủ hơn 15 giây. Xin lưu ý khi bạn đặt máy tính vào chế độ ngủ, phải mất thêm 15 giây nữa để lên ý tưởng cho tất cả các bộ xử lý. (Khi thử nghiệm trên PC MY).

(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.');
	}
});


Vui lòng giải thích lý do tại sao điều này sẽ không hoạt động, nếu nó không có trong trường hợp của bạn
Lasithds

-1

Tôi đã thực hiện chính xác yêu cầu tương tự bằng AWS Cognito, với Lambda Authorulators, & Redis, tôi không thể chia sẻ mã ở giai đoạn này nhưng tôi có thể cho bạn biết mọi thứ được thực hiện với các thành phần này, các khái niệm tương tự có thể được sử dụng với các thành phần khác các thành phần không AWS.

Trước tiên, với việc thực hiện đăng xuất không hoạt động, bạn sẽ phải thực hiện phía máy chủ, vì nếu ai đó chỉ cần tắt máy tính của họ, trang web mặt trước sẽ không đăng xuất. Tôi đã sử dụng khái niệm của ACTIVEngười dùng. Khi người dùng xác thực thành công, tôi lưu trữ với thời lượng 15 phút trong Redis một mục nhập có khóa username& giá trị của họ ACTIVE(có thể là tên người dùng + sessionid nếu bạn muốn cho phép nhiều phiên cho một người dùng nhất định cùng một lúc).

Trong Người ủy quyền tùy chỉnh của tôi khi người dùng là ACTIVE& họ có Mã thông báo hợp lệ, tôi cấp cho họ quyền truy cập vào tài nguyên được bảo vệ VÀ quan trọng nhất là tôi thực hiện một lệnh khác trong Redis với username& ACTIVE.

Bất cứ khi nào người dùng đăng xuất, tôi đăng xuất chúng trong giải pháp quản lý danh tính của mình (Cognito) và tôi đánh dấu chúng là INACTIVE. Lưu ý rằng nếu người dùng không truy cập API trong vòng 15 phút, họ sẽ không còn có mục nhập ACTIVEchống lại tên người dùng của mình và sẽ không thể truy cập API nữa và phải đăng nhập lại, họ sẽ được chuyển hướng để thực hiện.

Có rất nhiều điều cần xem xét với cách tiếp cận này, vì một điều thường là ủy quyền lưu trữ kết quả bộ đệm trong một khoảng thời gian và nếu nói rằng bạn lưu kết quả trong 5 phút làm ví dụ, thì người dùng của bạn có thể bị đăng xuất sau 10 phút với tư cách là người dùng của bạn có thể nhấn bộ đệm thay vì Authorizer sẽ không làm mới ACTIVEmục nhập.

Điều quan trọng nữa là bạn phải đảm bảo mọi thứ bạn sử dụng để lưu trữ nếu một người dùng nhất định ACTIVEsẵn sàng cao và sẽ phục hồi nhanh chóng trong trường hợp xảy ra lỗi.

Cách tiếp cận sử dụng bộ nhớ cache theo cách này tương tự như cách vô hiệu hóa mã thông báo được thêm vào các giao thức ủy quyền không trạng thái như OAuth2.

Chúng tôi đã sử dụng phương pháp này được vài tháng rồi, nó dường như hoạt động tốt với chúng tôi, nó có thể là một yêu cầu khó chịu để xử lý, tôi đã dự đoán trong thế giới AWS sẽ có sẵn sàng sử dụng về giải pháp hộp cho việc này nhưng không có gì để nói.


Chúng tôi cũng đã sống sót qua một bài kiểm tra bút (; Đây là nơi yêu cầu của chúng tôi xuất phát ban đầu, ứng dụng của chúng tôi là một sản phẩm dựa trên dịch vụ tài chính và chúng tôi phải thực hiện điều này như một yêu cầu.
Snickers3192
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.