3

我想根据管理员设置防止用户同时登录。

如果管理员将并发登录设置为 3,则用户可以同时从 3 个不同的地方登录。

如果用户尝试从第 4 位登录,则应用程序不应允许用户登录。

任何想法如何通过数据库维护它。请帮忙。提前致谢。

4

3 回答 3

5

您可以维护一个包含活动用户会话的数据库表,如果最后一个用户活动发生在 X 分钟之前(可配置值),则认为会话处于活动状态。

每次用户尝试通过登录表单进行身份验证时,您都应该检查该用户目前有多少会话处于活动状态,并根据该检查决定是对他进行身份验证还是使用某种形式的响应消息拒绝。

于 2012-07-05T11:20:34.037 回答
0

完整的工作示例(下载)

您所做的是向您的用户表添加一个额外的列,将其命名为登录名。每当用户登录时,将列增加 1,在您的登录脚本中,您可以检查登录次数是否等于限制,当用户注销时,您将登录次数减少 1。

使用此方法可能出现的一个问题是,如果用户没有注销并且服务器无法再次识别会话,则登录不会减少。为了避免这种情况,下面是一种更好的方法。

  1. 创建一个它登录的列名,并给它一个数据类型 varchar(500) 或者最好是文本,因为它可能很难预测我们期望的数据大小。

  2. 当用户登录时,检查 logins 列是否为空,如果为空,则使用 time() 函数创建一个包含 session_id、登录时间的 json。

    if($column_login == '' or count(json_decode($column_login)) == 0){
        $login_json = json_encode([
                        ['session_key'=>'session_key_generated', 'time' => time()]
                    ]);
    //then update the logins table with the above
    }
    
  3. 如果 logins 列不为空或解码时列的计数大于零,则检查计数是否大于 login limit ,如果登录数尚未大于 login limit,则附加新的与数据库表中登录列的会话

    if(count(json_decode($column_login)) > 0 and count(json_decode($column_login)) < $login_limit){
        $login_json = json_decode($column_login);
        $login_json[] = ['session_key'=>'session_key_generated', 'time' => time()];
        $login_json = json_encode($column_login);
        //update the logins column with the new $login_json and log the user in
    }
    
  4. 如果达到登录限制,则检查登录并检查是否有过期时间,例如,假设一个 300 秒的非活动用户已注销,然后从表中删除已过期的会话

    if(count(json_decode($column_login)) >= $limit){
        $logins = json_decode($column_login);
        foreach($logins as $key =>  $login){
            if($login['time'] < time()-300){
                //this checks if the iterated login is greater than the current time -300seconds and if found to be true then the user is inactive
                //then set this current login to null by using the below statement
                $logins[$key] = null; // or unset($logins[$key]) either should work;
    
            }
    
        }
    
        //after iteration we check if the count of logins is still greater than the limit
        if(count($logins) >= login_limit){
            //then return a login error that maximum logins reached
        }else{
            //then login is successsfull
        } 
        //update the logins column to equal to json_encode($logins);
    }
    
  5. 在登录用户发出的任何请求中,您检查会话密钥是否仍然存在于数据库的登录列 ($logins['session_key']),如果未找到,则立即注销用户以避免权利升级,否则将 $login['time'] 更新为新的 time()。

这种方法效果很好。

于 2018-03-20T12:28:04.340 回答
0

我已经基于@MaheshKathiriya 实现了一些东西

我有一个名为user“id”(PK,AI),“用户名”,“密码”,“登录”列的表
serialize()将数组转换为字符串,unserialize()并将序列化字符串转换回大批

在登录列中,我插入了一个包含子数组的数组(我们称之为 main_array)。
main_array 中的子数组数表示 DB 中注册的会话数。
子数组有两个值,session_id 和 time_of_login。

每当用户登录时,我们都会检查 main_array 中子数组的数量。

如果 main_array 为空,我们插入一个带有相应 session_id 和 time 的新子数组并允许用户登录。

否则,如果主数组不为空,我们检查其中有多少子数组。如果子数组的数量大于 0 且小于 login_limit,则我们插入一个新的子数组并允许用户登录。

否则,如果 main_array 中的子数组数量等于或大于 login_limit,则我们检查过期会话(sub_array['time']>time()-60, means this session was active more than 60 seconds ago)
如果会话在过去 60 秒内未处于活动状态,我们会从主数组中删除它的子数组。
现在我们再次检查 main_array 中子数组的数量是否等于或大于 login_limit,如果小于登录限制,我们允许登录并将新会话 sub_array 插入主数组。否则登录失败(因为没有活动会话可以替换当前尝试登录的用户)向 main_array 插入一个新的子数组,其中包含相应的 session_id 和登录时间。

<?php
if($_SERVER['REQUEST_METHOD']=='POST'){
  require('db_config.php');
  $session_id = session_id();
  $type = $_POST['type'];
  if($type=='login'){ //if user is trying to login
    $login_limit=3; //this is going to be the limit simultaneous logins
    $username=$_POST['username'];
    $password=$_POST['password'];
    $authenticated = false;

    $sql="select * from `user` where `username` = '$username' and `password` = '$password'";
    $result = $conn->query($sql);
    $count = mysqli_num_rows($result);
    if($count>0){
      $authenticated=true;
      $row = mysqli_fetch_assoc($result);
      $user_id = $row['id'];
    }
    else{
      $authenticated=false;
    }
    if($authenticated){ //doing it this way isn't necessary


      $get_login = "SELECT `login` FROM `user` WHERE  `username` = '$username' and `password` = '$password'";
      $result = $conn->query($get_login);
      $row = mysqli_fetch_assoc($result);
      $login_column = $row['login']; //this contains serialized array of login details;
      if($login_column=='' || count(unserialize($login_column))==0){ //if the column is empty i.e  it's first time login, or there are no users logged in
        echo "login column is empty <br>";
        $sub_array = array('s_key'=>$session_id,'time'=>time());
        $main_array=array($sub_array);

        //update login column
        $main_login = serialize($main_array);
        $update_login = "UPDATE `user` SET `login` = '$main_login' WHERE  `username` = '$username' and `password` = '$password'";
        $isUpdated = ($conn->query($update_login) && ($conn->affected_rows>0));
        if($isUpdated){
          echo "main 1 updated<br>";
          echo "login succesful<br>";
          $_SESSION['isLoggedIn']=true;
          $_SESSION['username']=$username;
          $_SESSION['password']=$password;
        }
        else{
          echo "main 1 not updated <br>";
        }
      }
      else if(count(unserialize($login_column))>0 && count(unserialize($login_column))<$login_limit){ //else if coulmn is not empty but doesn't have max simultaneous logins
        echo "Login column is not empty and has ".count(unserialize($login_column))." logins atm <br> Will insert this login now<br>";
        $main_array = unserialize($login_column);
        $sub_array = array('s_key'=>$session_id,'time'=>time());
        array_push($main_array,$sub_array);

        //update login column
        $main_login = serialize($main_array);
        $update_login = "UPDATE `user` SET `login` = '$main_login' WHERE  `username` = '$username' and `password` = '$password'";
        $isUpdated = ($conn->query($update_login) && ($conn->affected_rows>0));
        if($isUpdated){
          echo "main 2 updated<br>";
          echo "login succesful<br>";
          $_SESSION['isLoggedIn']=true;
          $_SESSION['username']=$username;
          $_SESSION['password']=$password;
        }
        else{
          echo "main 2 not updated <br>";
        }

      }
      else if(count(unserialize($login_column))>=$login_limit){ //else if max login has been reached,
        echo "limit reached in login column, now inactive sessions will be removed and this one will be logged in <br>";
        $logins = unserialize($login_column);
        foreach ($logins as $key => $value) {
          if($value['time']<time()-60){ //change 60 to whatever timelimit you want
            unset($logins[$key]);
          }
          // code...
        }
        //after iteration we check if the count of logins is still greater than the limit
        if(count($logins) >= $login_limit){
            //then return a login error that maximum logins reached
            echo "max logins reached, login FAILED!<br>";
        }else{
            //then login is successsfull
            echo "SUCCESS!<br>";
            $_SESSION['isLoggedIn']=true;
            $_SESSION['username']=$username;
            $_SESSION['password']=$password;

        //update login column
        $main_array = ($logins);
        $sub_array = array('s_key'=>$session_id,'time'=>time());
        array_push($main_array,$sub_array);
        $main_login = serialize($main_array);
        $update_login = "UPDATE `user` SET `login` = '$main_login' WHERE  `username` = '$username' and `password` = '$password'";
        $isUpdated = ($conn->query($update_login) && ($conn->affected_rows>0));
        if($isUpdated){
          echo "main 3 updated<br>";
        }
        else{
          echo "main 3 not updated <br>";
        }
      }

      }
      else{
        echo "something went wrong";
      }
    }
  }
  else if($type == 'logout'){
    // $_SESSION['isLoggedIn']=true;
    $username=$_SESSION['username'];
    $password=$_SESSION['password'];

    $get_login = "SELECT `login` FROM `user` WHERE  `username` = '$username' and `password` = '$password'";
    $result = $conn->query($get_login);
    $row = mysqli_fetch_assoc($result);
    $login_column = $row['login'];

    $searchLogin = unserialize($login_column);
    foreach ($searchLogin as $key => $login) {
      // code...
      if($login['s_key']==$session_id){
        echo "<br> session found: ".$login['s_key']."==".$session_id."<br>";
        unset($searchLogin[$key]);
      }
    }
    //update login column
    $main_array = ($searchLogin);
    // $sub_array = array('s_key'=>$session_id,'time'=>time());
    // array_push($main_array,$sub_array);
    $main_login = serialize($main_array);
    $update_login = "UPDATE `user` SET `login` = '$main_login' WHERE  `username` = '$username' and `password` = '$password'";
    $isUpdated = ($conn->query($update_login) && ($conn->affected_rows>0));
    if($isUpdated){
      echo "logged out<br>";
    }
    else{
      echo "FAILED Logout <br>";
    }


  }
}
?>
<form class="" action="index.php" method="post">
  <input type="text" name="username" value="">
  <input type="password" name="password" value="">
  <input type="hidden" name="type" value="login">
  <button type="submit" name="button">login</button>
</form>
<form class="" action="index.php" method="post">
  <input type="hidden" name="type" value="logout">
  <button type="submit" name="button">logout</button>

</form>
于 2020-04-14T12:48:19.030 回答