关于使用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。
前段时间做的一个项目大概也有这么一个东西,大概目的是只能有一个终端在登录这个账号,即不能一个账号多处同时登录。
解决办法是在数据库中添加了一个字段token,每次登录根据时间戳加其他的生成一个新的token,在整个过程中不断检测token,如果发生改变了,那说明有用户在别处登录。