我用PHP實現一個帳號只能同時在同一個裝置登入,注意,不是同一個IP。
之前是在MYSQL的表中加了個顯示是否登入了的欄位,若登入了設定為1,退出設定為0.
但後來發現,強行關閉瀏覽器的時候就沒辦法把這個欄位設定為0了!
想了很久沒想出解決方案,後來在網上看到好像可以用redis來實現,於是這兩天開始學redis。但發現這樣學下去也沒有什麼思路啊。
所以上來請教一下,請問有誰有經驗的可以說一下怎麼實現嗎?謝謝!祝大家中秋節快樂!
回複內容:
我用PHP實現一個帳號只能同時在同一個裝置登入,注意,不是同一個IP。
之前是在MYSQL的表中加了個顯示是否登入了的欄位,若登入了設定為1,退出設定為0.
但後來發現,強行關閉瀏覽器的時候就沒辦法把這個欄位設定為0了!
想了很久沒想出解決方案,後來在網上看到好像可以用redis來實現,於是這兩天開始學redis。但發現這樣學下去也沒有什麼思路啊。
所以上來請教一下,請問有誰有經驗的可以說一下怎麼實現嗎?謝謝!祝大家中秋節快樂!
如果是 Redis 的話, 可以使用 hash 結構來儲存賬戶登入資訊.
hash 的結構: key field value
hash 相關使用命令 http://redisdoc.com/hash/inde...
具體實現:
hash 結構中, 使用相同的 key field 寫入資料時, 會覆蓋掉曆史資料
Redis> hset key field TestRedis> hget key field"Test"Redis> hset key field RunRedis> hget key field"Run"
這樣就能實現單個賬戶的需求, 指定一個 key 用來儲存賬戶登入資訊, field 就是每個賬戶的主鍵, 那麼每次登入都會將上一次的登入資訊清空, 之前的登入資訊就失效了, 這樣就能達到之前的登入狀態失效.
如果考慮到不同裝置的登入, 可以將 field 變為 devicename-uid 這種形式, 保證一個裝置只能夠有一個登入資訊存在.
你要知道你需要什嗎?
單點登入還是限制單裝置
單裝置是同一台電腦多個瀏覽器?
關於使用mysql的一種解決方案
如果不考慮效率,只需要在mysql中你原有的記錄是否已登入的欄位旁再增加到期時間和裝置唯一識別碼兩個欄位,將以前的判斷是否登入的條件由“是否為1”變為“是否為1且未到期且裝置唯一識別碼一致”。每次使用者有操作時都更新到期時間的值,如果一段時間沒有操作,登入狀態就可以“自動”到期,這樣就可以解決你的“強行關閉瀏覽器的時候就沒辦法把這個欄位設定為0了”的問題。
使用phpredis進行簡單實現
如果你剛接觸redis,且僅僅需要用redis做使用者登入的控制,對於資料結構,你不是很瞭解,string類型即可滿足你(如果可以,使用hash可能會更好)。
下面以phpredis擴充提供的相關類作為背景,進行描述:
假設某一使用者id為100的賬戶登入,向redis中記錄登入裝置資訊
connect($redisHost, $redisPort); $cacheName = 'deviceUUID:user'.$userId; $deviceUUID = getDeviceUUID(); // 假設有 getDeviceUUID() 函數用於擷取/產生裝置的唯一識別碼 $timeout = 600; // 使用者10十分鐘無操作自動下線 $redis->set($cacheName, $deviceUUID); $redis->setTimeout($cacheName, $timeout);}
裝置每次執行其它操作前,都需要更新redis中裝置資訊的到期時間
connect($redisHost, $redisPort); $cacheName = 'deviceUUID:user'.$userId; $deviceUUID = getDeviceUUID(); // 假設有 getDeviceUUID() 函數用於擷取/產生裝置的唯一識別碼 $timeout = 600; // 使用者10十分鐘無操作自動下線 $cachedDeviceUUID = $redis->get($cacheName); $isTimeout = false === $cachedDeviceUUID; $isTheRightDevice = $deviceUUID === $cachedDeviceUUID; if($isTimeout || !$isTheRightDevice){ return false; } $redis->setTimeout($cacheName, $timeout); return true;}
裝置中使用者賬戶退出時,需要清理redis中的該裝置資訊
connect($redisHost, $redisPort); $cacheName = 'deviceUUID:user'.$userId; $redis->delete($cacheName);}
當然了,上面的使用string類型而不是散列類型來實現的解決方案在資源利用和效率上是不太合理的。如果你希望對redis有更深的瞭解和運用推薦你閱讀《Redis IN ACTION》這本書。具體到php中使用redis,你可以選擇使用phpredis擴充或predis。
前段時間做的一個項目大概也有這麼一個東西,大概目的是只能有一個終端在登入這個帳號,即不能一個帳號多處同時登入。
解決辦法是在資料庫中添加了一個欄位token,每次登入根據時間戳記加其他的產生一個新的token,在整個過程中不斷檢測token,如果發生改變了,那說明有使用者在別處登入。
資料庫加個欄位:臨時的token;等登入後,這個臨時的token會隨機產生,同時使用者會根據這個token產生對應的sesssion;當另外一個裝置登入後,臨時的token更新了;原有裝置的session無法匹配資料庫的token;就會自動跳出!