数字营销 · Web开发 · 基础设施

PHP用户登陆限制的实现

介绍 PHP 中限制用户同时登录数量的实现思路,从 Session 识别用户出发,通过记录和管理 Session ID,实现单账户单人登录以及多账户登录数量限制。

在哆麦询盘管理系统的开发过程中,遇到了这样一个问题:出于信息安全的考虑,希望给每个能够进入系统的人员一个独立账户,而不是所有人共用一个账户,并且一个账户同时只能有一个人登录。

刚开始的做法是登录加锁。当用户登录之后,对该用户进行标记,如果用户处于未下线状态,又进行了第二次登录尝试,则禁止其登录。

这样确实解决了单账户多用户同时登录的问题,但是实际操作中,却遇到了更大的问题:用户登录过程中进行了加锁,那么用户离开时就必须进行解锁操作,而很多用户离开网站的习惯是直接点击浏览器的关闭按钮,这就导致无法正常解锁,最终连用户自己正常登录也受到了限制。

PHP用户登陆限制的实现

那么,如何更加友好地限制用户账户的登录呢?

我们首先分析一下 PHP 是如何识别用户是否登录的。由于 HTTP 协议具有无状态性的特点,我们无法直接通过 HTTP 对用户进行识别。

一般来说,对用户的识别主要通过 Cookie 或 Session。它们最大的不同在于:Cookie 数据由客户端存储,每次向服务端发送请求时,客户端都会把有效的 Cookie 随请求发送到服务端;Session 数据则由服务端存储,服务端可以根据客户端发送的特定 Cookie 值,来判断这些请求是否属于同一个 Session。

我们可以通过下面的方式进行用户登录检测:

<?php
session_start();

if(isset($_SESSION['login']) && $_SESSION['login'] == true){
echo "登陆成功!";
}

if(isset($_POST['uname']) && isset($_POST['password'])){
$uname = $_POST['uname'];
$pass = $_POST['password'];

if($uname == "admin" && $pass == "admin"){
$_SESSION['login'] = true;
echo "登陆成功!";
}else{
echo "用户名或密码错误!";
}
}
?>

<form action="" method="post">
<input type="text" name="uname">
<input type="password" name="password">
<input type="submit">
</form>

显而易见,上面的代码并不能保证同一个账户同时只能登录一次。

第一种限制单账户登录次数的办法,是在登录时存储本次会话的 Session ID。当用户再次登录时,首先删除之前用户的 Session,再把本次登录的 Session 保存起来。这样一来,原来的用户就会被新用户挤下线。

<?php
define("session_path", dirname(__FILE__)."/session"); //设置Session存放的目录

session_save_path(session_path);
session_start();

if(isset($_SESSION['login']) && $_SESSION['login'] == true){
echo "登陆成功!";
}

if(isset($_POST['uname']) && isset($_POST['password'])){
$uname = $_POST['uname'];
$pass = $_POST['password'];

if($uname == "admin" && $pass == "admin"){
$_SESSION['login'] = true;
kick_user();
echo "登陆成功!";
}else{
echo "用户名或密码错误!";
}
}

function kick_user(){
$last_login_session_id = file_get_contents("loginsession.txt"); //获取上次登录的Session ID
$last_login_session_file = session_path."/sess_".$last_login_session_id;

if(session_id() != $last_login_session_id){
unlink($last_login_session_file);
file_put_contents("loginsession.txt", session_id());
}
}
?>

<form action="" method="post">
<input type="text" name="uname">
<input type="password" name="password">
<input type="submit">
</form>

在这个基础上,我们还可以对同一个账户同时登录的次数进行限制,只需要修改 kick_user() 函数:

function kick_user($num=1){
$last_login_session_id_file = file_get_contents("loginsession.txt"); //获取之前登录的Session ID
$last_login_session_id_arr = explode("|", $last_login_session_id_file);

if(!in_array(session_id(), $last_login_session_id_arr)){
array_push($last_login_session_id_arr, session_id());
}

if(count($last_login_session_id_arr) > $num) {
$rmsession = array_shift($last_login_session_id_arr);
}

if(isset($rmsession)){
unlink(session_path."/sess_".$rmsession);
}

file_put_contents(
"loginsession.txt",
implode("|", $last_login_session_id_arr)
);
}

这样就可以限制一个账户同时在线的数量。例如 $num=1 时,同一个账户只允许有一个 Session;当新的用户登录时,可以将原来的 Session 删除,使之前登录的用户自动下线。

从这个例子可以看到,与直接对“用户是否登录”进行加锁相比,通过记录和管理 Session ID 的方式更加灵活,也可以进一步扩展成限制同时登录数量、主动踢出用户等功能。

不过实际项目中,Session ID 最好不要直接保存在文本文件中,而应该放到数据库等更加可靠的存储中统一管理。

评论0

欢迎分享你的看法,也欢迎补充不同的实践经验。