1. 程式人生 > >redis實現session共享,解決一個賬號只能在一個終端登陸

redis實現session共享,解決一個賬號只能在一個終端登陸

一個賬號在a電腦登陸了,此時在b電腦登陸,就會將a踢下線,需要解決兩個問題:
一、確保賬號只能在一個地方登陸;
二、登陸後傳送訊息通知;

對於第一個問題,我們可以藉助於session儲存於redis之後,實現session在多個站點,多臺伺服器共享的情況下,統一通過session_id來管理使用者的session資料,

下面是一段session儲存於redis的程式碼並且展示了通過session_id去redis獲取session資料的例子。

$redis_config = ['host' => '192.168.200.229', 'port' => 6379];
@ini_set("session.save_handler", "redis");
@ini_set("session.save_path", 'tcp://'.$redis_config['host'].':'.$redis_config['port']);

session_start();
$_SESSION['user_id'] = 123;
$_SESSION['user_name'] = 'helin';
$_SESSION['email'] = '
[email protected]
'; $session_id = session_id(); echo $session_id; //ssr242gfioap1auk0njtdg07q4 echo "<br>"; $redis = new redis(); $redis->connect($redis_config['host'], $redis_config['port']); // redis 用 session_id 作為 key 並且是以 string 的形式儲存 echo $redis->get('PHPREDIS_SESSION:' . $session_id); //user_id|i:123;user_name|s:5:"helin";email|s:14:"
[email protected]
"; echo "<br>"; echo json_encode($_SESSION); //{"user_id":123,"user_name":"helin","email":"[email protected]"} exit;
有了上面程式碼的實現,我們可以思考一下具體實現的邏輯:
步驟一:使用者登陸的時候把session_id儲存到使用者資料表,然後根據uid來生成一個鍵,將一些使用者資訊儲存在redis裡面(生成一個登陸標識及session_id等);
步驟二:當另外一個終端用同一賬號登陸的時候,獲取到使用者表的session_id。並做步驟一的操作;
步驟三:通過步驟二獲取到的session_id就變成是舊的資訊了,有可能是當前在用的,也有可能是過期的,此時可以先根據這個session_id從redis清除掉裡面的資料,不管它是不是有效的;

通過上面的處理後,若在另外一個終端有登陸,那此時其它地方的session應該是被清除掉了,再訪問需要登陸的頁面的時候肯定是退出狀態;那麼第一個問題就算是解決了,現在來討論第二個問題:

如果實時性要求不高,而且也不需要考慮大資料的壓力,例如是一個ERP管理系統,公司內部用的,登陸的人一般不會太多,可以通過ajax定時請求輪詢方式實現,這樣會簡單很多,實現形式就是通過伺服器判斷當前的session資料是否還存在,若不存在了,根據之前儲存在redis裡面的登陸狀態資料及使用者資訊,查出此使用者表裡面儲存的session_id跟redis裡面儲存的session_id是否一致,如果是登陸狀態並且不一致,那就可以提示使用者已經在另外的終端登陸。如果是session_id一致,那應該可以肯定是過期了。此時可以清除掉使用者相關的redis資料然後做重定向登陸。
實時性要求高的,或者效能上面有考慮,可以使用socket的方式,與ajax方式不一樣的是它可以實時把資料推送到客戶端,這種使用者體驗最好,可控性強,就是實現起來稍微比第一種方式要複雜一點點,可以藉助socket.io + node.js的方式實現。

除了上面的方式,我們也可以換個思路,做最簡單的處理,當用戶在另外的終端登陸,當前可以直接退出,不做提示,當前如果需要做其它操作的時候,再去判斷登陸問題也是可以的,只不過沒有那麼實時,還有就是在規劃之初就要考慮到這個流程怎麼走使用者體驗會好一些。