簡體   English   中英

如何在php中限制每個用戶的並發登錄數

[英]How to limit the number of concurrent login per user in php

我想根據管理員設置阻止用戶並發登錄。

如果管理員將並發登錄設置為 3,則用戶可以同時從 3 個不同的地方登錄。

如果用戶嘗試從第 4 處登錄,則應用程序不應允許用戶登錄。

知道如何通過數據庫維護它。 請幫忙。 提前致謝。

您可以維護一個包含活動用戶會話的數據庫表,如果上次用戶活動發生在 X 分鍾之前(可配置值),則會話被視為活動。

每次用戶嘗試通過登錄表單進行身份驗證時,您應該檢查該用戶目前有多少個會話處於活動狀態,並根據該檢查決定是對他進行身份驗證還是使用某種形式的響應消息拒絕。

完整的工作示例(下載)

您所做的是在您的用戶表中添加一個額外的列,並將其命名為登錄。 每當用戶登錄時將列增加 1,並且在您的登錄腳本中,您可以檢查登錄次數是否等於限制,並且當用戶注銷時,您將登錄次數減少 1。

使用此方法可能出現的一個問題是,如果用戶未注銷並且服務器無法再次識別會話,則登錄名不會減少。 為了避免這種情況,下面是一種更好的方法。

  1. 創建一個它登錄的列名,並為其指定 varchar(500) 數據類型或最好是文本,因為可能很難預測我們期望的數據大小。

  2. 當用戶登錄時,檢查登錄列是否為空,如果為空,則使用 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. 如果登錄列不為空或解碼時該列的計數大於零,則檢查計數是否大於登錄限制,如果登錄數尚未大於登錄限制,則追加新的會話到數據庫表中的登錄列

    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()。

這種方法效果很好。

我已經實現了一些基於@MaheshKathiriya 的東西

我有一個名為user的表,其中包含“id”(PK,AI)、“用戶名”、“密碼”、“登錄”列
serialize()將數組轉換為字符串, unserialize()將序列化的字符串轉換回數組

在登錄列中,我插入了一個包含子數組的數組(我們稱之為 main_array)。
main_array 中子數組的個數表示數據庫中注冊會話的個數。
子數組有兩個值,session_id 和 time_of_login。

每當用戶登錄時,我們都會檢查 main_array 中子數組的數量。

如果 main_array 為空,我們插入一個具有相應 session_id 和時間的新子數組並允許用戶登錄。

否則如果主數組不為空,我們檢查其中有多少子數組。 如果子數組的數量大於 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>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM