Запрет многократного входа в систему с использованием одного имени пользователя и пароля - PullRequest
14 голосов
/ 19 декабря 2009

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

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

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

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

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

Ответы [ 12 ]

25 голосов
/ 19 декабря 2009

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

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

Самый простой способ - позволить User иметь переменную static Map<User, HttpSession> и позволить ему реализовать HttpSessionBindingListenerObject#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.

5 голосов
/ 30 января 2011

Создайте одну таблицу в вашей базе данных - назовем ее [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 голосов
/ 19 декабря 2009

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

хорошее решение все еще приветствуется

2 голосов
/ 08 февраля 2015

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

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

Вышеописанное работает, поскольку при каждом входе в систему создается НОВЫЙ response.session_id, который сохраняется в БД. Проверка выполняется только на целевой странице (которая в моем приложении является наиболее важной, инициирующей много других функций), поэтому не слишком много обращений к БД для вышеупомянутого. Вышеуказанное не зависит от выхода пользователя из системы. IP-адрес не используется (о чем упоминали другие, страдает от своих проблем) Это позволяет только ОДНОМУ пользователю войти в систему одновременно, и это выходит из системы "более старого" пользователя.

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

2 голосов
/ 19 декабря 2009

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

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

2 голосов
/ 19 декабря 2009

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

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

<listener>
   <listener-class>com.foo.MySessionListener</listener-class>
</listener>

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

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

Как определить, активен ли браузер или нет?

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

Примечание: Установка времени согласно вашему требованию (в моем случае это 1 минута).

Наряду с вышеуказанной проверкой состояния добавьте код, указанный в комментарии «Если пользователь закрывает браузер без выхода из системы».

public class User implements HttpSessionBindingListener 
0 голосов
/ 06 августа 2018

Используйте токен

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

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

Таблица:

userid:token:log_date
0 голосов
/ 20 февраля 2012

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

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

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

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

@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 ");
                } 
            }
        }
0 голосов
/ 19 декабря 2009

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

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

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

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

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