Предотrotation множественного входа с использованием одного и того же имени пользователя и пароля

Я разрабатываю приложение, которое необходимо для предотвращения множественного входа с использованием одного и того же имени пользователя и пароля.

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

Мы должны помнить следующее:

  1. Если пользователь закрывает браузер без выхода из системы.
  2. Если сеанс отключен.

Я был бы признателен за любую помощь в этом.

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

В частности, этот случай является трудным и не является надежным для обнаружения. Вы можете использовать событие beforeunload в Javascript, но вы полностью beforeunload от того, включен ли браузер в JS, и конкретный браузер поддерживает это нестандартное событие (например, Opera не работает). Это также одна из основных причин, по которой я предлагаю просто выйти из ранее зарегистрированного пользователя, вместо того, чтобы препятствовать логину. Это также более удобно и безопасно для случая, когда пользователь «забыл» выйти из другого компьютера.

Самый простой способ – предоставить User переменную static Map и позволить ей реализовать HttpSessionBindingListenerObject#equals() и Object#hashCode() ).

 public class User implements HttpSessionBindingListener { // All logins. private static Map logins = new HashMap(); // Normal properties. private Long id; private String username; // Etc.. Of course with public getters+setters. @Override public boolean equals(Object other) { return (other instanceof User) && (id != null) ? id.equals(((User) other).id) : (other == this); } @Override public int hashCode() { return (id != null) ? (this.getClass().hashCode() + id.hashCode()) : super.hashCode(); } @Override public void valueBound(HttpSessionBindingEvent event) { HttpSession session = logins.remove(this); if (session != null) { session.invalidate(); } logins.put(this, event.getSession()); } @Override public void valueUnbound(HttpSessionBindingEvent event) { logins.remove(this); } } 

Когда вы входите в систему User следующим образом:

 User user = userDAO.find(username, password); if (user != null) { request.getSession.setAttribute("user", user); } else { // Show error. } 

то он вызовет valueBound() который удалит любого ранее зарегистрированного пользователя из карты logins и аннулирует сеанс.

Когда вы выходите из системы User следующим образом:

 request.getSession().removeAttribute("user"); 

или когда сеанс завершен, тогда valueUnbound() , который удаляет пользователя из карты logins .

Создайте одну таблицу в своей базе данных – назовем ее [online_users] – тремя полями:

 [online_users] 1. username 2. login_time 3. logout_time 

Всякий раз, когда пользователь входит в систему, вставьте имя пользователя и время входа в [online_users] .

На всех страницах, требующих входа в систему, установите это условие: отметьте [online_users] чтобы узнать, является ли logout_time пользователя пустым или нет.

Всякий раз, когда пользователь нажимает кнопку выхода, установите logout_time в [online_users] для этого имени пользователя.

Если кто-то пытается войти в систему с активным именем пользователя и паролем, проверьте username и logout_time и покажите сообщение о том, что пользователь уже вошел в систему. И самое главное, установите для logout_time значение MULTIPLELOGIN для этого пользователя.

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

Возьмите одно дополнительное поле в таблице, в котором имя столбца скажет «IsLoggedIn» как поле бит и установите его значение true до тех пор, пока пользователь не войдет в систему. Как только пользователь выйдет из системы, установите значение false. Это необходимо сделать и для времени окончания сеанса. Как только сессия закончится, это поле должно быть автоматически установлено на false с помощью триггеров или через вызов SP

хорошее решение по-прежнему приветствуется

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

Чтобы «захватить» истечение сеанса, вам необходимо определить в вашем web.xml :

  com.foo.MySessionListener  

Где MySessionListener – это реализация интерфейса HttpSessionListener (предоставляемого API Servlet).

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

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

Может быть, слишком упрощен, но эй … он работает для меня в Web2Py:

Только при успешном входе в систему я пишу SessionID (response.session_id) в таблице auth_membership. На целевой странице (индексной странице) я проверяю, равен ли текущий response.session_id SessionID, поступающий из БД. Если так – все в порядке. Если нет – («старший», первый) пользователь вежливо выйдет из системы.

Вышеупомянутое работает, поскольку при каждом входе в базу данных создается и сохраняется NEW response.session_id. Проверка выполняется только на целевой странице (которая в моем приложении является самой важной, инициируя многие другие функции), поэтому не слишком много ударов БД для вышеуказанного. Вышеуказанное не зависит от выхода пользователя из системы. IP-адрес не задействован (что другие упомянули, он страдает от собственных проблем). Он позволяет одновременно регистрировать только пользователя ONE, и он выдает «более старый» пользователь.

Надеюсь, это поможет NeoToren

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

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

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

Это имеет смысл для вашего приложения?

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

Всякий раз, когда IP-адрес переключается, вы можете: а) истечь старого сеанса пользователя, поэтому они вынуждены заходить в систему и b) увеличивать счетчик для каждого пользователя (который вы можете обнулить каждый час). Если счетчик превышает 5 (или что-то еще), вы можете заблокировать весь доступ к учетной записи пользователя в течение более длительного периода времени.

Это можно легко выполнить, если у вас есть сеанс. Для каждого входа в браузер необходимо создать запись сеанса в базе данных сеанса. Идентификатор сеанса может использоваться как файл cookie проверки подлинности. Бит сеанса также имеет индекс с именем пользователя. При входе в систему вы можете запросить базу данных, чтобы проверить, сколько сеансов существует. Фактически мы разрешаем один сеанс для каждого типа. Например, пользователь может иметь логин с мобильного телефона и другой из браузера. Но он не может иметь 2 сеанса браузера.

Чтобы решить проблему, о которой вы говорили. У вас есть 2 варианта,

  1. У вас очень короткий тайм-аут сеанса (например, 5 минут) и продление сеанса при каждом использовании. Таким образом, пользователь будет автоматически выходить из системы, если выйдет без выхода из системы.

  2. Ударьте другую сессию. Новый сеанс ударяет по старой сессии. Сбитый сеанс остается в БД со специальным флагом в течение 24 часов. Мы показываем сообщение, чтобы сообщить пользователю о том, что другой сеанс подключен, и отображает время и IP. Таким образом, пользователь получит уведомление, если его учетная запись будет скомпрометирована.

Я реализовал возможное решение для себя,

в используемом loginFilter, я установил lastloggedin, userloggedin и userSession в записи пользователя в моей системе.

  user.setUser_lastlogged(new Date()); user.setUser_loggedin(true); user.setSessionId(request.getSession().getId()); appService.saveUsers(user); 

поэтому, когда я перехожу к любому из своих действий struts2, у меня есть fragment кода в методе подготовки.

 @Override public void prepare() throws Exception { UsersBase usercheck = appservice.getUserByUsername((String)request.getSession().getAttribute("j_username")); if(request.getSession().getId().equals(usercheck.getSessionId())){ request.getSession().invalidate(); } } 

Это приведет к регистрации пользователя при входе на другой компьютер, или если вы не хотите регистрировать их, я могу сделать следующее на loginFilter

  UsersBase userdto = appService.getUserByUsername(username); if (userdto != null) { if ((userdto.getUser_loggedin())) { if (request.getSession().getId().equals(userdto.getSessionId())) { authRequest.eraseCredentials(); request.getSession().setAttribute("error", "You are already logged in "); } } } 

Использовать токен

Когда пользователь вошел в систему успешно, сторона сервера возвращает строку токена стороне клиента / браузера, а на стороне сервера сохраняется карта с идентификатором userID. Клиент неоднократно проверяет / запрашивает сервер с этим токеном, если токен не является таким же, этот пользователь регистрирует несколько раз.

При выходе из системы он сохраняет токен в cookies или файловой системы на стороне клиента и приносит этот токен при входе в следующий раз.

Таблица:

 userid:token:log_date 
  • Как вы возвращаете объект JSON из Java-сервлета
  • Что означает значение сервлета
  • Запуск JSF 2.0 на контейнере Servlet 2.4
  • Внедрение простого сервлета загрузки файлов
  • HTTP Status 405 - HTTP-метод GET не поддерживается этим URL-адресом
  • Обнаружение отключения клиента в сервлете tomcat?
  • Почему Spring MVC отвечает 404 и сообщает «Нет сопоставления для HTTP-запроса с URI в DispatcherServlet»?
  • Получение контекста сервлетов, сеанса и запроса в внешнем контейнере POJO
  • Обмен данными сеанса между контекстами в Tomcat
  • Метод getDispatcherType () не определен для типа HttpServletRequest
  • Отправить файл как multipart через xmlHttpRequest
  • Давайте будем гением компьютера.