首页  >  问答  >  正文

一个账号同时只能在同一个设备上登陆

我用PHP实现一个账号只能同时在同一个设备登录,注意,不是同一个IP。
之前是在MYSQL的表中加了个显示是否登录了的字段,若登录了设置为1,退出设置为0.
但后来发现,强行关闭浏览器的时候就没办法把这个字段设置为0了!
想了很久没想出解决方案,后来在网上看到好像可以用redis来实现,于是这两天开始学redis。但发现这样学下去也没有什么思路啊。
所以上来请教一下,请问有谁有经验的可以说一下怎么实现吗?

高洛峰高洛峰2872 天前2240

全部回复(3)我来回复

  • 三叔

    三叔2016-11-11 10:22:16

    数据库加个字段:临时的token;等登录后,这个临时的token会随机生成,同时用户会根据这个token生成对应的sesssion;当另外一个设备登录后,临时的token更新了;原有设备的session无法匹配数据库的token;就会自动跳出!

    回复
    0
  • 欧阳克

    欧阳克2016-11-11 10:22:02

    前段时间做的一个项目大概也有这么一个东西,大概目的是只能有一个终端在登录这个账号,即不能一个账号多处同时登录。

    解决办法是在数据库中添加了一个字段token,每次登录根据时间戳加其他的生成一个新的token,在整个过程中不断检测token,如果发生改变了,那说明有用户在别处登录。


    回复
    0
  • 三叔

    三叔2016-11-11 10:21:50

    关于使用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。

    回复
    0
  • 取消回复