一個帳號同時只能在同一個設備上登錄

一個帳號同時只能在同一個設備上登錄

我用PHP實現一個帳號只能同時在同一個設備登陸,注意,不是同一個IP。
以前是在MYSQL的表中加了個顯示是否登陸了的字段,若登陸了設置爲1,退出設置爲0.
但後來發現,強行關閉瀏覽器的時候就沒辦法把這個字段設置爲0了!
想了好久沒想出解決方案,後來在網上看到好像能夠用redis來實現,因而這兩天開始學redis。但發現這樣學下去也沒有什麼思路啊。
因此上來請教一下,請問有誰有經驗的能夠說一下怎麼實現嗎?謝謝!祝你們中秋節快樂!php

  •  

5個回答

答案對人有幫助,有參考價值0答案沒幫助,是錯誤的答案,答非所問html

採納mysql

若是是 Redis 的話, 可使用 hash 結構來存儲帳戶登入信息.git

hash 的結構: key field valuegithub

hash 相關使用命令 http://redisdoc.com/hash/inde...redis

具體實現:sql

hash 結構中, 使用相同的 key field 寫入數據時, 會覆蓋掉歷史數據數據庫

Redis> hset key field Test
Redis> hget key field
"Test"
Redis> hset key field Run
Redis> hget key field
"Run"

這樣就能實現單個帳戶的需求, 指定一個 key 用來存儲帳戶登入信息, field 就是每一個帳戶的主鍵, 那麼每次登陸都會將上一次的登入信息清空, 以前的登入信息就失效了, 這樣就能達到以前的登陸狀態失效.segmentfault

若是考慮到不一樣設備的登陸, 能夠將 field 變爲 devicename-uid 這種形式, 保證一個設備只可以有一個登陸信息存在.瀏覽器

答案對人有幫助,有參考價值1答案沒幫助,是錯誤的答案,答非所問

關於使用mysql的一種解決方法

若是不考慮效率,只須要在mysql中你原有的記錄是否已登陸的字段旁再增長過時時間設備惟一標識符兩個字段,將之前的判斷是否登陸的條件由「是否爲1」變爲「是否爲1且未過時且設備惟一標識符一致」。每次用戶有操做時都更新過時時間的值,若是一段時間沒有操做,登陸狀態就能夠「自動」過時,這樣就能夠解決你的「強行關閉瀏覽器的時候就沒辦法把這個字段設置爲0了」的問題。

使用phpredis進行簡單實現

若是你剛接觸redis,且僅僅須要用redis作用戶登陸的控制,對於數據結構,你不是很瞭解,string類型便可知足你(若是能夠,使用hash可能會更好)。

下面以phpredis擴展提供的相關類做爲背景,進行描述:

假設某一用戶id爲100的帳戶登陸,向redis中記錄登陸設備信息

<?php
/**
 * 註冊用戶登陸設備信息
 * 
 * 登陸後向redis中寫入登陸的設備標識信息,若是在此以前已經登陸了別的設備,以前登陸的設備將被強制下線
 */
function registerUserDevice()
{
    $userId = 100; // 假設用戶id爲100
    $redis = new Redis();
    $redisHost = '127.0.0.1';
    $redisPort = 6379;
    $redis->connect($redisHost, $redisPort);
    $cacheName = 'deviceUUID:user'.$userId; 
    $deviceUUID = getDeviceUUID(); // 假設有 getDeviceUUID() 函數用於獲取/生成設備的惟一標識符
    $timeout = 600; // 用戶10十分鐘無操做自動下線
    $redis->set($cacheName, $deviceUUID);
    $redis->setTimeout($cacheName, $timeout);
}

設備每次執行其它操做前,都須要更新redis中設備信息的過時時間

<?php
/**
 * 延長redis中設備標識信息的生存時間
 *
 * 從新設置redis中用戶設備標識信息的過時時間
 * @return bool true = 更新成功, false = 更新失敗,當前設備須要從新登陸
 */
function extendDeviceInfoTTL()
{
    $userId = 100; // 假設用戶id爲100
    $redis = new Redis();
    $redisHost = '127.0.0.1';
    $redisPort = 6379;
    $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中的該設備信息

<?php
/**
 * 銷燬用戶設備信息
 * 
 * 用在執行登出操做時
 */
function delUserDevice()
{
    $userId = 100; // 假設用戶id爲100
    $redis = new Redis();
    $redisHost = '127.0.0.1';
    $redisPort = 6379;
    $redis->connect($redisHost, $redisPort);
    $cacheName = 'deviceUUID:user'.$userId; 
    $redis->delete($cacheName);
}

固然了,上面的使用string類型而不是散列類型來實現的解決方案在資源利用和效率上是不太合理的。若是你但願對redis有更深的瞭解和運用推薦你閱讀《Redis IN ACTION》這本書。具體到php中使用redis,你能夠選擇使用phpredis擴展predis

答案對人有幫助,有參考價值1答案沒幫助,是錯誤的答案,答非所問

前段時間作的一個項目大概也有這麼一個東西,大概目的是隻能有一個終端在登陸這個帳號,即不能一個帳號多處同時登陸。

解決辦法是在數據庫中添加了一個字段token,每次登陸根據時間戳加其餘的生成一個新的token,在整個過程當中不斷檢測token,若是發生改變了,那說明有用戶在別處登陸。

  •  

答案對人有幫助,有參考價值0答案沒幫助,是錯誤的答案,答非所問

你要知道你須要什麼?
單點登陸仍是限制單設備
單設備是同一臺電腦多個瀏覽器?

  •  

答案對人有幫助,有參考價值0答案沒幫助,是錯誤的答案,答非所問

數據庫加個字段:臨時的token;等登陸後,這個臨時的token會隨機生成,同時用戶會根據這個token生成對應的sesssion;當另一個設備登陸後,臨時的token更新了;原有設備的session沒法匹配數據庫的token;就會自動跳出!

相關文章
相關標籤/搜索