Предотвращение множественного входа с использованием одного и того же имени пользователя и пароля
Я разрабатываю приложение, которое необходимо для предотвращения множественного входа с использованием одного и того же имени пользователя и пароля.
Если это происходит на одной и той же машине, то, очевидно, нам нужно что-то сделать с сеансом пользователя, но это также должно помешать, если они будут входить в систему на разных компьютерах, используя одно и то же имя пользователя и пароль.
Мы должны помнить следующее:
- Если пользователь закрывает браузер без выхода из системы.
- Если время ожидания сеанса.
Буду признателен за любую помощь в этом.
Ответы
Ответ 1
Если пользователь закрывает браузер без выхода из системы.
В частности, этот случай является трудным и не является надежным для обнаружения. Вы можете использовать событие beforeunload
в Javascript, но вы полностью зависите от того, включен ли браузер в JS, и конкретный браузер поддерживает это нестандартное событие (например, Opera не работает). Это также одна из основных причин, по которой я предлагаю просто выйти из ранее зарегистрированного пользователя, вместо того, чтобы препятствовать логину. Это также более удобно и безопасно для случая, когда пользователь "забыл" выйти из другого компьютера.
Самый простой способ - позволить User
иметь переменную static Map<User, HttpSession>
и позволить ей реализовать HttpSessionBindingListener
(и Object#equals()
и Object#hashCode()
).
public class User implements HttpSessionBindingListener {
// All logins.
private static Map<User, HttpSession> logins = new HashMap<User, HttpSession>();
// 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
.
Ответ 2
Создайте одну таблицу в своей базе данных - позвоните ей [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
для этого пользователя.
Если этот пользователь вошел в систему на любом другом компьютере, то, если он обновляется или переходит на другую страницу, сайт сообщает ему, что он вышел из системы. Затем пользователь может быть перенаправлен на домашнюю страницу сайта.
Ответ 3
Возьмите одно дополнительное поле в таблице, в котором имя столбца скажет "IsLoggedIn" как поле бит и установите его значение true до тех пор, пока пользователь не войдет в систему. Как только пользователь выйдет из системы, установите значение false.
Это необходимо сделать и для времени окончания сеанса.
Как только сессия закончится, это поле должно быть автоматически установлено на false с помощью триггеров или через вызов SP
хорошее решение по-прежнему приветствуется
Ответ 4
Я бы также посоветовал решение Shantanu Gupta - иметь столбец базы данных, указывающий, что пользователь в настоящее время зарегистрирован, и соответствующим образом обновить этот столбец.
Чтобы "захватить" истечение сеанса, вам необходимо определить в web.xml
:
<listener>
<listener-class>com.foo.MySessionListener</listener-class>
</listener>
Где MySessionListener
- это ваша реализация интерфейса HttpSessionListener
(предоставляемая API-интерфейсом Servlet).
Ответ 5
Я бы просто предложил использовать систему безопасности для обработки всех этих деталей для вас. Spring Безопасность, например, довольно легко интегрируется в существующий проект, может быть настроена довольно сильно, если это необходимо - и, самое главное, имеет встроенную поддержку для обнаружения и управления одновременными входами.
Не заново изобретайте колесо, когда это не нужно, иначе вы потратите немало времени на создание ухабистого колеса.
Ответ 6
Может быть, слишком упрощен, но эй... он работает для меня в Web2Py:
Только при успешном входе в систему я пишу SessionID (response.session_id) в таблице auth_membership.
На целевой странице (индексной странице) я проверяю, равен ли текущий response.session_id SessionID, поступающий из БД.
Если так - все в порядке.
Если нет - ( "старший", первый) пользователь вежливо выходил из системы.
Вышеупомянутое работает, поскольку при каждом входе в базу данных создается и сохраняется NEW response.session_id.
Проверка выполняется только на целевой странице (которая в моем приложении является самой важной, инициируя многие другие функции), поэтому не слишком много ударов БД для вышеуказанного.
Вышеуказанное не зависит от выхода пользователя из системы.
Нет IP-адреса (которые другие упомянули, страдает от собственных проблем)
Он позволяет только одному пользователю регистрироваться одновременно, и он выдает "более старого" пользователя.
Надеюсь, что это поможет
NeoToren
Ответ 7
Я проследил бы каждый последний известный IP-адрес пользователя и отметку времени, когда они были последними на этом IP-адресе. Затем вы можете просто заблокировать доступ с других IP-адресов в течение 5 минут, часа или всего, что вам нравится.
Всякий раз, когда IP-адрес переключается, вы можете: a) истечь старый сеанс пользователя, поэтому они вынуждены заходить в систему и b) увеличивать счетчик для каждого пользователя (который вы можете обнулить каждый час). Если счетчик превышает 5 (или что-то еще), вы можете заблокировать весь доступ к учетной записи пользователя в течение более длительного периода времени.
Ответ 8
Вы можете сохранить какой-либо идентификатор сеанса для пользователя при входе в систему. Когда пользователь выходит из системы или когда истекает срок действия сеанса, вы снова удаляете эту информацию.
Когда пользователь пытается войти в систему, и у вас уже есть идентификатор сеанса, сохраненный для этого пользователя, пусть пользователь подтвердит это, а затем аннулирует старый сеанс.
Пользователь, разумеется, захочет снова войти в систему сразу же, если браузер разбился или что-то в этом роде, так что позволить пользователю дождаться окончания сеанса может раздражать.
Это имеет смысл для вашего приложения?
Ответ 9
Это может быть легко применено, если у вас есть сеанс. Для каждого входа в браузер необходимо создать запись сеанса в базе данных сеанса. Идентификатор сеанса может использоваться как файл cookie проверки подлинности. Бит сеанса также имеет индекс с именем пользователя. При входе в систему вы можете запросить базу данных, чтобы проверить, сколько сеансов существует. Фактически мы разрешаем один сеанс для каждого типа. Например, пользователь может иметь логин с мобильного телефона и другой из браузера. Но он не может иметь 2 сеанса браузера.
Чтобы решить проблему, о которой вы говорили. У вас есть 2 варианта,
-
У вас очень короткий тайм-аут сеанса (например, 5 минут) и продление сеанса при каждом использовании. Таким образом, пользователь будет автоматически выходить из системы, если оставить его без выхода из системы.
-
Ударьте другой сеанс. Новый сеанс ударяет по старой сессии. Сбитый сеанс остается в БД со специальным флагом в течение 24 часов. Мы показываем сообщение, чтобы сообщить пользователю о том, что другой сеанс подключен, и отображает время и IP. Таким образом, пользователь получит уведомление, если их учетная запись подвергается риску.
Ответ 10
Я внедрил для себя возможное решение,
в используемом loginFilter, я установил lastloggedin, userloggedin и userSession в записи пользователя в моей системе.
user.setUser_lastlogged(new Date());
user.setUser_loggedin(true);
user.setSessionId(request.getSession().getId());
appService.saveUsers(user);
поэтому, когда я перехожу к любому из моих действий struts2, у меня есть фрагмент кода в методе подготовки.
@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 ");
}
}
}
Ответ 11
Используйте токен
Когда пользователь входит в систему успешно, серверная сторона возвращает строку токена стороне клиента/браузера, а серверная сторона сохраняет карту с токеном userID. Клиент неоднократно проверяет/запрашивает сервер с этим токеном, если токен не совпадает, этот пользователь регистрируется несколько раз.
При выходе из системы он сохраняет токен в куки или файловую систему на стороне клиента и переносит этот токен при следующем входе в систему.
Таблица:
userid:token:log_date
Ответ 12
Как определить, активен ли браузер или нет?
Совершайте фиктивный вызов ajax каждую минуту и записывайте состояние в HttpSession для пользователя, идентификатор сеанса и время последнего вызова. Когда тот же пользователь входит в новый сеанс, проверьте его в HttpSession и проверьте, превышает ли оно время больше
чем минута, это означает, что предыдущий браузер закрыт/не активен.
Примечание: установка времени согласно вашему требованию (в моем случае это 1 минута).
Наряду с вышеуказанной проверкой условий добавьте код, указанный в комментарии "Если пользователь закрыл браузер без выхода из системы".
public class User implements HttpSessionBindingListener