Как предотвратить несколько входов в систему на сайте PHP - PullRequest
17 голосов
/ 13 ноября 2009

Я хочу предотвратить несколько входов в php-приложение.

Сначала я создаю статус входа (активный, нотационный) в пользовательской таблице.

Когда пользователь A входит в систему, статус пользователя будет установлен как «активный», а если пользователь выходит из системы, статус будет установлен как «notactive». Когда другой клиент пытается войти, используя ту же учетную запись, я проверяю таблицу пользователей. Если пользователь все еще активен, пользователю будет отправлено сообщение об ошибке.

Проблема возникла, если пользователь закрывает браузер, состояние в пользовательской таблице может быть обновлено, потому что пользователь не щелкнул выход из системы.

У вас есть предложения по этому поводу?

Ответы [ 7 ]

18 голосов
/ 13 ноября 2009

(Обратите внимание, что хотя этот метод все еще в некоторой степени действителен; образцы PHP не следует копировать дословно, поскольку существуют более безопасные способы включения пользовательских значений в запрос SQL)


Вместо того, чтобы хранить, активен ли пользователь \ неактивен, лучше хранить некоторый атрибут, который может быть проверен против пользователя для каждого отдельного действия; например, каждый раз, когда пользователь пытается выполнить что-то, требующее аутентификации, он проверяет, совпадает ли этот атрибут, прежде чем он продолжит работу.

Я рекомендую вам сделать следующее;

Во-первых, создайте хеш для уникальной идентификации пользователя при каждом входе в систему. Я думаю, что sha1 из time() будет достаточно, чтобы избежать коллизий. Что бы вы ни выбрали, убедитесь, что он достаточно разнообразен, чтобы другой пользователь, вошедший в систему, имел невероятно низкий шанс получить тот же хеш (например, не хэшируйте IP-адрес или пользовательский агент браузера, поскольку они не меняются). достаточно).

Во-вторых, сохраните этот хеш в своей базе данных и в пользовательском сеансе во время входа в систему. Это позволит эффективно «выйти» из системы предыдущего пользователя, поскольку хэш должен каждый раз отличаться вход в систему.

Поскольку мы используем сеансы, в браузер пользователя должен автоматически помещаться файл cookie, который будет содержать уникальный идентификатор, который идентифицирует пользователя по его или ее данным сеанса. Содержимое файла cookie не имеет значения.

Затем создайте функцию с именем authenticateUser() или аналогичную, которая будет вызываться в начале каждого сценария для проверки подлинности пользователя. Этот сценарий должен запрашивать базу данных, проверяя, есть ли у пользователя с идентификатором вашего пользователя хеш, соответствующий хешу вашего пользователя.

Например:

function authenticateUser($id, $hash, $databaseLink) {
    # SQL
    $sql = 'SELECT EXISTS(
               SELECT 1
               FROM `tbl_users`
               WHERE `id` = \''.mysql_real_escape_string($id).'\'
               AND `hash` = \''.mysql_real_escape_string($hash).'\'
               LIMIT 1
           );';

    # Run Query
    if ($query = mysql_query($sql, $databaseLink)) {
        # Get the first row of the results
        # Assuming 'id' is your primary key, there
        # should only ever be one row anyway.       
        $result = mysql_fetch_row($query);

        # Casting to boolean isn't strictly necessary here
        # its included to indicate the mysql result should
        # only ever been 1 or 0.
        return (bool)($result[0]);
    } else {
        # Query error :(
        return false;
    }
}

Затем мы просто передаем authenticateUser() пользователя ID, hash (для данных вашего сеанса) и database link (для соединения с базой данных, которое вам придется открыть ранее).

Если authenticateUser() возвращает true, пользователь проходит проверку подлинности. Если false, пользователь не ИЛИ база данных недоступна или возникла ошибка SQL.

Обратите внимание, что это увеличит нагрузку на ваш сервер, так как запрос к базе данных отправляется один раз на запрос страницы Вероятно, не все так мудро делать это в гигантских проектах, в которые тысячи людей входят в систему в любой момент времени. Я уверен, что кто-то может предложить улучшения.

Кроме того, ожидание истечения срока действия файла cookie не лучший способ заставить людей, которые были неактивны, выходить из системы, поскольку вы никогда не должны доверять файлам cookie. Вместо этого вы можете добавить столбец с именем last_active, который можно обновлять каждый раз при аутентификации пользователя. Это также увеличит нагрузку на сервер, но позволит вам вручную отменить устаревшие входы в систему, удалив hash для пользователей, которые были, скажем, неактивны в течение 3 часов.

8 голосов
/ 22 мая 2013

Вот решение, которое не требует постоянного доступа к базе данных для работы ...

(что избавит от необходимости проверять session_id () по значению базы данных каждый раз, когда вы запрашиваете / обновляете страницу, снимая нагрузку на БД / сервер) ...

1. При входе в систему захватите существующий идентификатор_ сеанса, сохраненный в БД для этого пользователя, и сделайте следующее:

session_id("the pre-existing session id in the database goes here");
session_start();
session_destroy();

2. Затем запустите новый сеанс и сохраните этот новый session_id в базе данных, перезаписав предыдущий. Это приведет к выходу из предыдущего сеанса на этом пользователе, если есть один активный (эффективный выход другого пользователя с использованием этой учетной записи).

Дайте ему попытку и дайте мне знать, если это поможет !!

6 голосов
/ 13 ноября 2009

Что вы должны сделать, это проверить, были ли они активны последние несколько минут при попытке войти в систему. Это может быть сделано с отметкой lastonline и должно быть установлено при каждом запросе страницы в пользовательской таблице.

Если с javascript это еще не сделано, вы можете при входе в систему проверить, был ли пользователь активен последние 15 минут. Если нет, то вы можете войти как новый пользователь.

Вы также можете сделать это с помощью JavaScript. Сделайте вызов ajax, который срабатывает каждую минуту или около того.

<script>
setInterval(function() {
  // do the ajax call
}, 60000);
</script>

Позвольте этому вызову перейти к сценарию, который отредактирует штамп lastonline в пользовательской базе данных. При попытке входа в систему вы проверяете пользователя db, если отметка lastonline превысила минуту, и у вас есть проверка, можете ли вы войти в систему. Это поможет, когда вы находитесь на странице, но вы не активны последние 15 минут и не хотите, чтобы кто-то еще входил в систему.

5 голосов
/ 13 ноября 2009

Вы можете изменить модель, чтобы в нее мог войти только самый последний пользователь.

Если вы записываете последний идентификатор сеанса, видимый для каждого пользователя, при повторном входе в систему вы можете удалить любой существующий в данный момент сеанс, эффективно отключив его.

Для обычного пользователя, вещи, похоже, "просто работают". Если вы хотите запретить «ненормальным» пользователям распространять свои учетные данные, это должно послужить сдерживающим фактором.

1 голос
/ 19 января 2012

Вам необходимо создать уникальный идентификатор и сохранить его в базе данных. То, что я сделал, было тоже создать. Я храню одну в переменной сеанса и использую ее для предотвращения перехвата сеанса, а другую в базе данных для предотвращения нескольких входов в систему. Следующий код создаст уникальный идентификатор:

$unique_id = sha1('xzr4'.gethostbyaddr($_SERVER['REMOTE_ADDR']).$random_string.$_SERVER['HTTP_USER_AGENT'].'f8k2');

Если уникальный идентификатор не совпадает, вы просто выходите из системы.

0 голосов
/ 14 июня 2019

Это решение похоже на prograhammer, но не требует от вас возиться с переключением сеансов. Он не требует доступа к базе данных на каждой странице и не блокирует пользователя после того, как ему не удалось выйти из системы.

Добавьте поле для sessionID в вашу таблицу пользователей в базе данных.

Установить обработчик сеанса по умолчанию перед вызовом session_start () (необходим для работы следующей строки кода):

session_set_save_handler(new \SessionHandler());

При каждом успешном входе в систему извлекайте сохраненный $ sessionID из базы данных. Уничтожить старый сеанс с помощью:

(new \SessionHandler())->destroy($sessionID);

Получить новый идентификатор сеанса с помощью:

$sessionID = session_id();

Сохранить новый идентификатор сеанса в базе данных.

0 голосов
/ 13 ноября 2009

Использование клиентского JavaScript для отслеживания входа пользователя ненадежно.

Вы можете получить тот же результат, просто создав поле lastlogindate в БД и обновив его, указав время последнего входа пользователя в систему.

При каждой попытке входа в систему, если now () - $ lastlogindate> prefined__timeout, вы должны принять новый вход в систему, в противном случае отказаться от него.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...